@autofleet/sadot 1.6.18-beta.2 → 1.6.18-beta.21

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 (162) hide show
  1. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/decorate.cjs +11 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/decorate.js +10 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/decorateMetadata.cjs +8 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/decorateMetadata.js +7 -0
  5. package/dist/_virtual/rolldown_runtime.cjs +43 -0
  6. package/dist/{chunk-DJulfCLt.js → _virtual/rolldown_runtime.js} +1 -2
  7. package/dist/api/index.cjs +12 -0
  8. package/dist/api/index.js +11 -0
  9. package/dist/api/v1/definition/index.cjs +113 -0
  10. package/dist/api/v1/definition/index.js +112 -0
  11. package/dist/api/v1/definition/validations.cjs +128 -0
  12. package/dist/api/v1/definition/validations.js +125 -0
  13. package/dist/api/v1/errors.cjs +14 -0
  14. package/dist/api/v1/errors.js +13 -0
  15. package/dist/api/v1/field-policies/index.cjs +104 -0
  16. package/dist/api/v1/field-policies/index.js +103 -0
  17. package/dist/api/v1/index.cjs +16 -0
  18. package/dist/api/v1/index.js +15 -0
  19. package/dist/api/v1/validator/index.cjs +132 -0
  20. package/dist/api/v1/validator/index.js +131 -0
  21. package/dist/api/v1/validator/validations.cjs +40 -0
  22. package/dist/api/v1/validator/validations.d.cts +22 -0
  23. package/dist/api/v1/validator/validations.d.ts +22 -0
  24. package/dist/api/v1/validator/validations.js +38 -0
  25. package/dist/errors/index.cjs +62 -0
  26. package/dist/errors/index.js +55 -0
  27. package/dist/events/index.cjs +52 -0
  28. package/dist/events/index.js +50 -0
  29. package/dist/hooks/enrich.cjs +175 -0
  30. package/dist/hooks/enrich.js +175 -0
  31. package/dist/hooks/find.cjs +22 -0
  32. package/dist/hooks/find.js +22 -0
  33. package/dist/hooks/hooks.cjs +310 -0
  34. package/dist/hooks/hooks.js +302 -0
  35. package/dist/hooks/index.cjs +3 -0
  36. package/dist/hooks/index.js +5 -0
  37. package/dist/hooks/utils/updateInstanceValues.cjs +27 -0
  38. package/dist/hooks/utils/updateInstanceValues.js +27 -0
  39. package/dist/index.cjs +48 -33508
  40. package/dist/index.d.cts +13 -396
  41. package/dist/index.d.ts +14 -394
  42. package/dist/index.js +21 -33435
  43. package/dist/init-state.cjs +56 -0
  44. package/dist/init-state.d.cts +35 -0
  45. package/dist/init-state.d.ts +35 -0
  46. package/dist/init-state.js +55 -0
  47. package/dist/mat-path-state.cjs +10 -0
  48. package/dist/mat-path-state.js +9 -0
  49. package/dist/migrations/001-create-core-tables.cjs +70 -0
  50. package/dist/migrations/001-create-core-tables.js +68 -0
  51. package/dist/migrations/002-create-custom-field-entries.cjs +27 -0
  52. package/dist/migrations/002-create-custom-field-entries.js +25 -0
  53. package/dist/migrations/003-create-custom-field-model-type-map.cjs +35 -0
  54. package/dist/migrations/003-create-custom-field-model-type-map.js +33 -0
  55. package/dist/migrations/004-create-field-policy-tables.cjs +29 -0
  56. package/dist/migrations/004-create-field-policy-tables.js +27 -0
  57. package/dist/migrations/005-add-entity-type-to-field-policies.cjs +20 -0
  58. package/dist/migrations/005-add-entity-type-to-field-policies.js +18 -0
  59. package/dist/migrations/index.cjs +94 -0
  60. package/dist/migrations/index.js +95 -0
  61. package/dist/models/CustomFieldDefinition.cjs +147 -0
  62. package/dist/models/CustomFieldDefinition.d.cts +40 -0
  63. package/dist/models/CustomFieldDefinition.d.ts +40 -0
  64. package/dist/models/CustomFieldDefinition.js +146 -0
  65. package/dist/models/CustomFieldEntries.cjs +71 -0
  66. package/dist/models/CustomFieldEntries.d.cts +15 -0
  67. package/dist/models/CustomFieldEntries.d.ts +15 -0
  68. package/dist/models/CustomFieldEntries.js +70 -0
  69. package/dist/models/CustomFieldModelTypeMap.cjs +62 -0
  70. package/dist/models/CustomFieldModelTypeMap.d.cts +14 -0
  71. package/dist/models/CustomFieldModelTypeMap.d.ts +14 -0
  72. package/dist/models/CustomFieldModelTypeMap.js +61 -0
  73. package/dist/models/CustomFieldValue.cjs +109 -0
  74. package/dist/models/CustomFieldValue.d.cts +20 -0
  75. package/dist/models/CustomFieldValue.d.ts +20 -0
  76. package/dist/models/CustomFieldValue.js +108 -0
  77. package/dist/models/CustomValidator.cjs +68 -0
  78. package/dist/models/CustomValidator.d.cts +18 -0
  79. package/dist/models/CustomValidator.d.ts +18 -0
  80. package/dist/models/CustomValidator.js +67 -0
  81. package/dist/models/FieldPolicy.cjs +54 -0
  82. package/dist/models/FieldPolicy.d.cts +25 -0
  83. package/dist/models/FieldPolicy.d.ts +25 -0
  84. package/dist/models/FieldPolicy.js +53 -0
  85. package/dist/models/index.cjs +163 -0
  86. package/dist/models/index.d.ts +11 -0
  87. package/dist/models/index.js +161 -0
  88. package/dist/models/tests/AssociatedTestModel.cjs +51 -0
  89. package/dist/models/tests/AssociatedTestModel.d.ts +2 -0
  90. package/dist/models/tests/AssociatedTestModel.js +50 -0
  91. package/dist/models/tests/TestModel.cjs +43 -0
  92. package/dist/models/tests/TestModel.d.ts +2 -0
  93. package/dist/models/tests/TestModel.js +42 -0
  94. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.cjs +35 -0
  95. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.d.ts +2 -0
  96. package/dist/models/tests/contextAwareModels/ContextAwareTestModel.js +34 -0
  97. package/dist/models/tests/contextAwareModels/ContextTestModel.cjs +33 -0
  98. package/dist/models/tests/contextAwareModels/ContextTestModel.d.ts +1 -0
  99. package/dist/models/tests/contextAwareModels/ContextTestModel.js +32 -0
  100. package/dist/repository/definition.cjs +221 -0
  101. package/dist/repository/definition.js +212 -0
  102. package/dist/repository/entries.cjs +69 -0
  103. package/dist/repository/entries.js +67 -0
  104. package/dist/repository/field-policy.cjs +69 -0
  105. package/dist/repository/field-policy.d.cts +35 -0
  106. package/dist/repository/field-policy.d.ts +35 -0
  107. package/dist/repository/field-policy.js +59 -0
  108. package/dist/repository/utils/formatValues.cjs +14 -0
  109. package/dist/repository/utils/formatValues.js +14 -0
  110. package/dist/repository/validator.cjs +85 -0
  111. package/dist/repository/validator.js +78 -0
  112. package/dist/repository/value.cjs +77 -0
  113. package/dist/repository/value.js +76 -0
  114. package/dist/scopes/filter.cjs +56 -0
  115. package/dist/scopes/filter.d.cts +22 -0
  116. package/dist/scopes/filter.d.ts +22 -0
  117. package/dist/scopes/filter.js +54 -0
  118. package/dist/scopes/helpers/filter.helpers.cjs +152 -0
  119. package/dist/scopes/helpers/filter.helpers.d.cts +16 -0
  120. package/dist/scopes/helpers/filter.helpers.d.ts +16 -0
  121. package/dist/scopes/helpers/filter.helpers.js +147 -0
  122. package/dist/scopes/index.cjs +1 -0
  123. package/dist/scopes/index.js +3 -0
  124. package/dist/types/index.d.cts +75 -0
  125. package/dist/types/index.d.ts +76 -0
  126. package/dist/utils/constants/index.cjs +32 -0
  127. package/dist/utils/constants/index.d.cts +23 -0
  128. package/dist/utils/constants/index.d.ts +23 -0
  129. package/dist/utils/constants/index.js +29 -0
  130. package/dist/utils/db/index.cjs +15 -0
  131. package/dist/utils/db/index.js +14 -0
  132. package/dist/utils/helpers/index.cjs +23 -0
  133. package/dist/utils/helpers/index.d.cts +30 -0
  134. package/dist/utils/helpers/index.d.ts +30 -0
  135. package/dist/utils/helpers/index.js +21 -0
  136. package/dist/utils/init.cjs +115 -0
  137. package/dist/utils/init.js +111 -0
  138. package/dist/utils/logger/index.cjs +15 -0
  139. package/dist/utils/logger/index.js +12 -0
  140. package/dist/utils/scopeAttributes.cjs +12 -0
  141. package/dist/utils/scopeAttributes.js +11 -0
  142. package/dist/utils/validations/index.cjs +34 -0
  143. package/dist/utils/validations/index.js +32 -0
  144. package/dist/utils/validations/schema/custom-fields.cjs +9 -0
  145. package/dist/utils/validations/schema/custom-fields.d.cts +6 -0
  146. package/dist/utils/validations/schema/custom-fields.d.ts +6 -0
  147. package/dist/utils/validations/schema/custom-fields.js +7 -0
  148. package/dist/utils/validations/schema/validator-schema.cjs +102 -0
  149. package/dist/utils/validations/schema/validator-schema.js +99 -0
  150. package/dist/utils/validations/validators/index.cjs +45 -0
  151. package/dist/utils/validations/validators/index.js +42 -0
  152. package/dist/utils/validations/validators/multi-select-dropdown.validator.cjs +7 -0
  153. package/dist/utils/validations/validators/multi-select-dropdown.validator.js +7 -0
  154. package/dist/utils/validations/validators/multi-select-status.validator.cjs +10 -0
  155. package/dist/utils/validations/validators/multi-select-status.validator.js +10 -0
  156. package/dist/utils/validations/validators/multi-select.helpers.cjs +12 -0
  157. package/dist/utils/validations/validators/multi-select.helpers.js +10 -0
  158. package/dist/utils/validations/validators/select.validator.cjs +12 -0
  159. package/dist/utils/validations/validators/select.validator.js +10 -0
  160. package/dist/utils/validations/validators/status.validator.cjs +12 -0
  161. package/dist/utils/validations/validators/status.validator.js +10 -0
  162. package/package.json +4 -4
@@ -0,0 +1,56 @@
1
+
2
+ //#region src/init-state.ts
3
+ /**
4
+ * Tracks the initialization state of sadot's useCustomFields function
5
+ * Allows HealthManager to wait for initialization before passing readiness checks
6
+ */
7
+ var SadotInitializationState = class {
8
+ constructor() {
9
+ this.initPromise = null;
10
+ this.initError = null;
11
+ this.isInitialized = false;
12
+ this.sequelizeInstance = null;
13
+ this.ownsSequelizeInstance = false;
14
+ }
15
+ /** Set the initialization promise */
16
+ setInitPromise(promise, ownsSequelize) {
17
+ this.initPromise = promise;
18
+ this.ownsSequelizeInstance = ownsSequelize;
19
+ promise.then((sequelize) => {
20
+ this.sequelizeInstance = sequelize;
21
+ this.isInitialized = true;
22
+ }, (error) => this.initError = error);
23
+ }
24
+ /**
25
+ * Get the Sequelize instance
26
+ * Returns null if initialization hasn't completed yet, or in cases where it failed.
27
+ */
28
+ get sequelize() {
29
+ return this.sequelizeInstance;
30
+ }
31
+ /**
32
+ * Wait for initialization to complete and return the Sequelize instance
33
+ * Returns the Sequelize instance only if Sadot created it (owns it)
34
+ * Returns undefined if the Sequelize instance was provided externally
35
+ * Rejects when initialization fails
36
+ */
37
+ async waitForInitialization() {
38
+ if (this.isInitialized && this.sequelizeInstance) return this.ownsSequelizeInstance ? this.sequelizeInstance : void 0;
39
+ if (this.initError) throw this.initError;
40
+ if (!this.initPromise) throw new Error("Sadot initialization has not started");
41
+ const sequelize = await this.initPromise;
42
+ if (this.initError) throw this.initError;
43
+ return this.ownsSequelizeInstance ? sequelize : void 0;
44
+ }
45
+ /** Check if initialization is complete and successful */
46
+ get isReady() {
47
+ return this.isInitialized && !this.initError;
48
+ }
49
+ /** Get the initialization error if one occurred */
50
+ get error() {
51
+ return this.initError;
52
+ }
53
+ };
54
+
55
+ //#endregion
56
+ exports.SadotInitializationState = SadotInitializationState;
@@ -0,0 +1,35 @@
1
+ import { Sequelize } from "sequelize-typescript";
2
+
3
+ //#region src/init-state.d.ts
4
+
5
+ /**
6
+ * Tracks the initialization state of sadot's useCustomFields function
7
+ * Allows HealthManager to wait for initialization before passing readiness checks
8
+ */
9
+ declare class SadotInitializationState {
10
+ private initPromise;
11
+ private initError;
12
+ private isInitialized;
13
+ private sequelizeInstance;
14
+ private ownsSequelizeInstance;
15
+ /** Set the initialization promise */
16
+ setInitPromise(promise: Promise<Sequelize>, ownsSequelize: boolean): void;
17
+ /**
18
+ * Get the Sequelize instance
19
+ * Returns null if initialization hasn't completed yet, or in cases where it failed.
20
+ */
21
+ get sequelize(): Sequelize | null;
22
+ /**
23
+ * Wait for initialization to complete and return the Sequelize instance
24
+ * Returns the Sequelize instance only if Sadot created it (owns it)
25
+ * Returns undefined if the Sequelize instance was provided externally
26
+ * Rejects when initialization fails
27
+ */
28
+ waitForInitialization(): Promise<Sequelize | undefined>;
29
+ /** Check if initialization is complete and successful */
30
+ get isReady(): boolean;
31
+ /** Get the initialization error if one occurred */
32
+ get error(): Error | null;
33
+ }
34
+ //#endregion
35
+ export { SadotInitializationState };
@@ -0,0 +1,35 @@
1
+ import { Sequelize } from "sequelize-typescript";
2
+
3
+ //#region src/init-state.d.ts
4
+
5
+ /**
6
+ * Tracks the initialization state of sadot's useCustomFields function
7
+ * Allows HealthManager to wait for initialization before passing readiness checks
8
+ */
9
+ declare class SadotInitializationState {
10
+ private initPromise;
11
+ private initError;
12
+ private isInitialized;
13
+ private sequelizeInstance;
14
+ private ownsSequelizeInstance;
15
+ /** Set the initialization promise */
16
+ setInitPromise(promise: Promise<Sequelize>, ownsSequelize: boolean): void;
17
+ /**
18
+ * Get the Sequelize instance
19
+ * Returns null if initialization hasn't completed yet, or in cases where it failed.
20
+ */
21
+ get sequelize(): Sequelize | null;
22
+ /**
23
+ * Wait for initialization to complete and return the Sequelize instance
24
+ * Returns the Sequelize instance only if Sadot created it (owns it)
25
+ * Returns undefined if the Sequelize instance was provided externally
26
+ * Rejects when initialization fails
27
+ */
28
+ waitForInitialization(): Promise<Sequelize | undefined>;
29
+ /** Check if initialization is complete and successful */
30
+ get isReady(): boolean;
31
+ /** Get the initialization error if one occurred */
32
+ get error(): Error | null;
33
+ }
34
+ //#endregion
35
+ export { SadotInitializationState };
@@ -0,0 +1,55 @@
1
+ //#region src/init-state.ts
2
+ /**
3
+ * Tracks the initialization state of sadot's useCustomFields function
4
+ * Allows HealthManager to wait for initialization before passing readiness checks
5
+ */
6
+ var SadotInitializationState = class {
7
+ constructor() {
8
+ this.initPromise = null;
9
+ this.initError = null;
10
+ this.isInitialized = false;
11
+ this.sequelizeInstance = null;
12
+ this.ownsSequelizeInstance = false;
13
+ }
14
+ /** Set the initialization promise */
15
+ setInitPromise(promise, ownsSequelize) {
16
+ this.initPromise = promise;
17
+ this.ownsSequelizeInstance = ownsSequelize;
18
+ promise.then((sequelize) => {
19
+ this.sequelizeInstance = sequelize;
20
+ this.isInitialized = true;
21
+ }, (error) => this.initError = error);
22
+ }
23
+ /**
24
+ * Get the Sequelize instance
25
+ * Returns null if initialization hasn't completed yet, or in cases where it failed.
26
+ */
27
+ get sequelize() {
28
+ return this.sequelizeInstance;
29
+ }
30
+ /**
31
+ * Wait for initialization to complete and return the Sequelize instance
32
+ * Returns the Sequelize instance only if Sadot created it (owns it)
33
+ * Returns undefined if the Sequelize instance was provided externally
34
+ * Rejects when initialization fails
35
+ */
36
+ async waitForInitialization() {
37
+ if (this.isInitialized && this.sequelizeInstance) return this.ownsSequelizeInstance ? this.sequelizeInstance : void 0;
38
+ if (this.initError) throw this.initError;
39
+ if (!this.initPromise) throw new Error("Sadot initialization has not started");
40
+ const sequelize = await this.initPromise;
41
+ if (this.initError) throw this.initError;
42
+ return this.ownsSequelizeInstance ? sequelize : void 0;
43
+ }
44
+ /** Check if initialization is complete and successful */
45
+ get isReady() {
46
+ return this.isInitialized && !this.initError;
47
+ }
48
+ /** Get the initialization error if one occurred */
49
+ get error() {
50
+ return this.initError;
51
+ }
52
+ };
53
+
54
+ //#endregion
55
+ export { SadotInitializationState };
@@ -0,0 +1,10 @@
1
+
2
+ //#region src/mat-path-state.ts
3
+ /**
4
+ * Module-scoped holder for the optional `isMatPathEnabled` predicate so route handlers can
5
+ * read it without threading the option through every layer. Set once during `useCustomFields()`.
6
+ */
7
+ const matPathState = {};
8
+
9
+ //#endregion
10
+ exports.matPathState = matPathState;
@@ -0,0 +1,9 @@
1
+ //#region src/mat-path-state.ts
2
+ /**
3
+ * Module-scoped holder for the optional `isMatPathEnabled` predicate so route handlers can
4
+ * read it without threading the option through every layer. Set once during `useCustomFields()`.
5
+ */
6
+ const matPathState = {};
7
+
8
+ //#endregion
9
+ export { matPathState };
@@ -0,0 +1,70 @@
1
+
2
+ //#region src/migrations/001-create-core-tables.ts
3
+ const up = async ({ context: queryInterface }) => {
4
+ const { sequelize } = queryInterface;
5
+ await sequelize.query(`
6
+ CREATE TABLE IF NOT EXISTS "custom_field_definitions" (
7
+ "id" UUID NOT NULL DEFAULT gen_random_uuid(),
8
+ "name" VARCHAR NOT NULL,
9
+ "display_name" VARCHAR,
10
+ "field_type" VARCHAR NOT NULL,
11
+ "validation" JSONB,
12
+ "entity_id" UUID NOT NULL,
13
+ "entity_type" VARCHAR NOT NULL,
14
+ "model_type" VARCHAR NOT NULL,
15
+ "description" TEXT,
16
+ "required" BOOLEAN DEFAULT false,
17
+ "disabled" BOOLEAN DEFAULT false,
18
+ "default_value" JSONB,
19
+ "block_editing_from_u_i" BOOLEAN NOT NULL DEFAULT false,
20
+ "created_at" TIMESTAMPTZ NOT NULL,
21
+ "updated_at" TIMESTAMPTZ,
22
+ "deleted_at" TIMESTAMPTZ,
23
+ PRIMARY KEY ("id")
24
+ )
25
+ `);
26
+ await sequelize.query(`
27
+ CREATE UNIQUE INDEX IF NOT EXISTS "unique_name_model_type"
28
+ ON "custom_field_definitions" ("model_type", "entity_id", "name")
29
+ `);
30
+ await sequelize.query(`
31
+ CREATE TABLE IF NOT EXISTS "custom_field_values" (
32
+ "model_id" UUID NOT NULL,
33
+ "custom_field_definition_id" UUID NOT NULL
34
+ REFERENCES "custom_field_definitions" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
35
+ "value" JSONB,
36
+ "created_at" TIMESTAMPTZ NOT NULL,
37
+ "updated_at" TIMESTAMPTZ,
38
+ "deleted_at" TIMESTAMPTZ,
39
+ PRIMARY KEY ("model_id", "custom_field_definition_id")
40
+ )
41
+ `);
42
+ await sequelize.query(`
43
+ CREATE INDEX IF NOT EXISTS "idx_custom_field_values_active_definition_id"
44
+ ON "custom_field_values" ("custom_field_definition_id")
45
+ WHERE "deleted_at" IS NULL
46
+ `);
47
+ await sequelize.query(`
48
+ CREATE TABLE IF NOT EXISTS "custom_validators" (
49
+ "id" UUID NOT NULL DEFAULT gen_random_uuid(),
50
+ "entity_id" UUID NOT NULL,
51
+ "entity_type" VARCHAR NOT NULL,
52
+ "model_type" VARCHAR NOT NULL,
53
+ "schema" JSONB NOT NULL,
54
+ "disabled" BOOLEAN NOT NULL DEFAULT false,
55
+ "created_at" TIMESTAMPTZ NOT NULL,
56
+ "updated_at" TIMESTAMPTZ,
57
+ PRIMARY KEY ("id")
58
+ )
59
+ `);
60
+ };
61
+ const down = async ({ context: queryInterface }) => {
62
+ const { sequelize } = queryInterface;
63
+ await sequelize.query("DROP TABLE IF EXISTS \"custom_field_values\"");
64
+ await sequelize.query("DROP TABLE IF EXISTS \"custom_field_definitions\"");
65
+ await sequelize.query("DROP TABLE IF EXISTS \"custom_validators\"");
66
+ };
67
+
68
+ //#endregion
69
+ exports.down = down;
70
+ exports.up = up;
@@ -0,0 +1,68 @@
1
+ //#region src/migrations/001-create-core-tables.ts
2
+ const up = async ({ context: queryInterface }) => {
3
+ const { sequelize } = queryInterface;
4
+ await sequelize.query(`
5
+ CREATE TABLE IF NOT EXISTS "custom_field_definitions" (
6
+ "id" UUID NOT NULL DEFAULT gen_random_uuid(),
7
+ "name" VARCHAR NOT NULL,
8
+ "display_name" VARCHAR,
9
+ "field_type" VARCHAR NOT NULL,
10
+ "validation" JSONB,
11
+ "entity_id" UUID NOT NULL,
12
+ "entity_type" VARCHAR NOT NULL,
13
+ "model_type" VARCHAR NOT NULL,
14
+ "description" TEXT,
15
+ "required" BOOLEAN DEFAULT false,
16
+ "disabled" BOOLEAN DEFAULT false,
17
+ "default_value" JSONB,
18
+ "block_editing_from_u_i" BOOLEAN NOT NULL DEFAULT false,
19
+ "created_at" TIMESTAMPTZ NOT NULL,
20
+ "updated_at" TIMESTAMPTZ,
21
+ "deleted_at" TIMESTAMPTZ,
22
+ PRIMARY KEY ("id")
23
+ )
24
+ `);
25
+ await sequelize.query(`
26
+ CREATE UNIQUE INDEX IF NOT EXISTS "unique_name_model_type"
27
+ ON "custom_field_definitions" ("model_type", "entity_id", "name")
28
+ `);
29
+ await sequelize.query(`
30
+ CREATE TABLE IF NOT EXISTS "custom_field_values" (
31
+ "model_id" UUID NOT NULL,
32
+ "custom_field_definition_id" UUID NOT NULL
33
+ REFERENCES "custom_field_definitions" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
34
+ "value" JSONB,
35
+ "created_at" TIMESTAMPTZ NOT NULL,
36
+ "updated_at" TIMESTAMPTZ,
37
+ "deleted_at" TIMESTAMPTZ,
38
+ PRIMARY KEY ("model_id", "custom_field_definition_id")
39
+ )
40
+ `);
41
+ await sequelize.query(`
42
+ CREATE INDEX IF NOT EXISTS "idx_custom_field_values_active_definition_id"
43
+ ON "custom_field_values" ("custom_field_definition_id")
44
+ WHERE "deleted_at" IS NULL
45
+ `);
46
+ await sequelize.query(`
47
+ CREATE TABLE IF NOT EXISTS "custom_validators" (
48
+ "id" UUID NOT NULL DEFAULT gen_random_uuid(),
49
+ "entity_id" UUID NOT NULL,
50
+ "entity_type" VARCHAR NOT NULL,
51
+ "model_type" VARCHAR NOT NULL,
52
+ "schema" JSONB NOT NULL,
53
+ "disabled" BOOLEAN NOT NULL DEFAULT false,
54
+ "created_at" TIMESTAMPTZ NOT NULL,
55
+ "updated_at" TIMESTAMPTZ,
56
+ PRIMARY KEY ("id")
57
+ )
58
+ `);
59
+ };
60
+ const down = async ({ context: queryInterface }) => {
61
+ const { sequelize } = queryInterface;
62
+ await sequelize.query("DROP TABLE IF EXISTS \"custom_field_values\"");
63
+ await sequelize.query("DROP TABLE IF EXISTS \"custom_field_definitions\"");
64
+ await sequelize.query("DROP TABLE IF EXISTS \"custom_validators\"");
65
+ };
66
+
67
+ //#endregion
68
+ export { down, up };
@@ -0,0 +1,27 @@
1
+
2
+ //#region src/migrations/002-create-custom-field-entries.ts
3
+ const up = async ({ context: queryInterface }) => {
4
+ const { sequelize } = queryInterface;
5
+ await sequelize.query(`
6
+ CREATE TABLE IF NOT EXISTS "custom_field_entries" (
7
+ "model_id" UUID NOT NULL,
8
+ "entity_id" UUID NOT NULL,
9
+ "custom_fields" JSONB NOT NULL DEFAULT '{}',
10
+ "model_type" VARCHAR NOT NULL,
11
+ "created_at" TIMESTAMPTZ NOT NULL,
12
+ "updated_at" TIMESTAMPTZ,
13
+ PRIMARY KEY ("model_id")
14
+ )
15
+ `);
16
+ await sequelize.query(`
17
+ CREATE INDEX IF NOT EXISTS "idx_cfe_custom_fields"
18
+ ON "custom_field_entries" USING gin ("custom_fields" jsonb_path_ops)
19
+ `);
20
+ };
21
+ const down = async ({ context: queryInterface }) => {
22
+ await queryInterface.sequelize.query("DROP TABLE IF EXISTS \"custom_field_entries\"");
23
+ };
24
+
25
+ //#endregion
26
+ exports.down = down;
27
+ exports.up = up;
@@ -0,0 +1,25 @@
1
+ //#region src/migrations/002-create-custom-field-entries.ts
2
+ const up = async ({ context: queryInterface }) => {
3
+ const { sequelize } = queryInterface;
4
+ await sequelize.query(`
5
+ CREATE TABLE IF NOT EXISTS "custom_field_entries" (
6
+ "model_id" UUID NOT NULL,
7
+ "entity_id" UUID NOT NULL,
8
+ "custom_fields" JSONB NOT NULL DEFAULT '{}',
9
+ "model_type" VARCHAR NOT NULL,
10
+ "created_at" TIMESTAMPTZ NOT NULL,
11
+ "updated_at" TIMESTAMPTZ,
12
+ PRIMARY KEY ("model_id")
13
+ )
14
+ `);
15
+ await sequelize.query(`
16
+ CREATE INDEX IF NOT EXISTS "idx_cfe_custom_fields"
17
+ ON "custom_field_entries" USING gin ("custom_fields" jsonb_path_ops)
18
+ `);
19
+ };
20
+ const down = async ({ context: queryInterface }) => {
21
+ await queryInterface.sequelize.query("DROP TABLE IF EXISTS \"custom_field_entries\"");
22
+ };
23
+
24
+ //#endregion
25
+ export { down, up };
@@ -0,0 +1,35 @@
1
+
2
+ //#region src/migrations/003-create-custom-field-model-type-map.ts
3
+ const up = async ({ context: queryInterface }) => {
4
+ const { sequelize } = queryInterface;
5
+ await sequelize.query(`
6
+ CREATE TABLE IF NOT EXISTS "custom_field_model_type_map" (
7
+ "id" UUID NOT NULL DEFAULT gen_random_uuid(),
8
+ "model_type_id" UUID NOT NULL,
9
+ "custom_field_definition_id" UUID NOT NULL
10
+ REFERENCES "custom_field_definitions" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
11
+ "created_at" TIMESTAMPTZ NOT NULL,
12
+ "updated_at" TIMESTAMPTZ NOT NULL,
13
+ PRIMARY KEY ("id")
14
+ )
15
+ `);
16
+ await sequelize.query(`
17
+ CREATE UNIQUE INDEX IF NOT EXISTS "unique_model_type_custom_field"
18
+ ON "custom_field_model_type_map" ("model_type_id", "custom_field_definition_id")
19
+ `);
20
+ await sequelize.query(`
21
+ CREATE INDEX IF NOT EXISTS "idx_custom_field_model_type_map_definition_id"
22
+ ON "custom_field_model_type_map" ("custom_field_definition_id")
23
+ `);
24
+ await sequelize.query(`
25
+ CREATE INDEX IF NOT EXISTS "idx_custom_field_model_type_map_type_id"
26
+ ON "custom_field_model_type_map" ("model_type_id")
27
+ `);
28
+ };
29
+ const down = async ({ context: queryInterface }) => {
30
+ await queryInterface.sequelize.query("DROP TABLE IF EXISTS \"custom_field_model_type_map\"");
31
+ };
32
+
33
+ //#endregion
34
+ exports.down = down;
35
+ exports.up = up;
@@ -0,0 +1,33 @@
1
+ //#region src/migrations/003-create-custom-field-model-type-map.ts
2
+ const up = async ({ context: queryInterface }) => {
3
+ const { sequelize } = queryInterface;
4
+ await sequelize.query(`
5
+ CREATE TABLE IF NOT EXISTS "custom_field_model_type_map" (
6
+ "id" UUID NOT NULL DEFAULT gen_random_uuid(),
7
+ "model_type_id" UUID NOT NULL,
8
+ "custom_field_definition_id" UUID NOT NULL
9
+ REFERENCES "custom_field_definitions" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
10
+ "created_at" TIMESTAMPTZ NOT NULL,
11
+ "updated_at" TIMESTAMPTZ NOT NULL,
12
+ PRIMARY KEY ("id")
13
+ )
14
+ `);
15
+ await sequelize.query(`
16
+ CREATE UNIQUE INDEX IF NOT EXISTS "unique_model_type_custom_field"
17
+ ON "custom_field_model_type_map" ("model_type_id", "custom_field_definition_id")
18
+ `);
19
+ await sequelize.query(`
20
+ CREATE INDEX IF NOT EXISTS "idx_custom_field_model_type_map_definition_id"
21
+ ON "custom_field_model_type_map" ("custom_field_definition_id")
22
+ `);
23
+ await sequelize.query(`
24
+ CREATE INDEX IF NOT EXISTS "idx_custom_field_model_type_map_type_id"
25
+ ON "custom_field_model_type_map" ("model_type_id")
26
+ `);
27
+ };
28
+ const down = async ({ context: queryInterface }) => {
29
+ await queryInterface.sequelize.query("DROP TABLE IF EXISTS \"custom_field_model_type_map\"");
30
+ };
31
+
32
+ //#endregion
33
+ export { down, up };
@@ -0,0 +1,29 @@
1
+
2
+ //#region src/migrations/004-create-field-policy-tables.ts
3
+ const up = async ({ context: queryInterface }) => {
4
+ const { sequelize } = queryInterface;
5
+ await sequelize.query(`
6
+ CREATE TABLE IF NOT EXISTS "field_policies" (
7
+ "id" UUID NOT NULL DEFAULT gen_random_uuid(),
8
+ "context_id" UUID NOT NULL,
9
+ "name" VARCHAR NOT NULL,
10
+ "fields" JSONB NOT NULL DEFAULT '[]',
11
+ "models" JSONB NOT NULL DEFAULT '[]',
12
+ "created_at" TIMESTAMPTZ NOT NULL,
13
+ "updated_at" TIMESTAMPTZ,
14
+ PRIMARY KEY ("id")
15
+ )
16
+ `);
17
+ await sequelize.query(`
18
+ CREATE UNIQUE INDEX IF NOT EXISTS "unique_context_policy"
19
+ ON "field_policies" ("context_id", "name")
20
+ `);
21
+ };
22
+ const down = async ({ context: queryInterface }) => {
23
+ const { sequelize } = queryInterface;
24
+ await sequelize.query("DROP TABLE IF EXISTS \"field_policies\"");
25
+ };
26
+
27
+ //#endregion
28
+ exports.down = down;
29
+ exports.up = up;
@@ -0,0 +1,27 @@
1
+ //#region src/migrations/004-create-field-policy-tables.ts
2
+ const up = async ({ context: queryInterface }) => {
3
+ const { sequelize } = queryInterface;
4
+ await sequelize.query(`
5
+ CREATE TABLE IF NOT EXISTS "field_policies" (
6
+ "id" UUID NOT NULL DEFAULT gen_random_uuid(),
7
+ "context_id" UUID NOT NULL,
8
+ "name" VARCHAR NOT NULL,
9
+ "fields" JSONB NOT NULL DEFAULT '[]',
10
+ "models" JSONB NOT NULL DEFAULT '[]',
11
+ "created_at" TIMESTAMPTZ NOT NULL,
12
+ "updated_at" TIMESTAMPTZ,
13
+ PRIMARY KEY ("id")
14
+ )
15
+ `);
16
+ await sequelize.query(`
17
+ CREATE UNIQUE INDEX IF NOT EXISTS "unique_context_policy"
18
+ ON "field_policies" ("context_id", "name")
19
+ `);
20
+ };
21
+ const down = async ({ context: queryInterface }) => {
22
+ const { sequelize } = queryInterface;
23
+ await sequelize.query("DROP TABLE IF EXISTS \"field_policies\"");
24
+ };
25
+
26
+ //#endregion
27
+ export { down, up };
@@ -0,0 +1,20 @@
1
+
2
+ //#region src/migrations/005-add-entity-type-to-field-policies.ts
3
+ const up = async ({ context: queryInterface }) => {
4
+ const { sequelize } = queryInterface;
5
+ await sequelize.query(`
6
+ ALTER TABLE "field_policies"
7
+ ADD COLUMN IF NOT EXISTS "entity_type" VARCHAR
8
+ `);
9
+ };
10
+ const down = async ({ context: queryInterface }) => {
11
+ const { sequelize } = queryInterface;
12
+ await sequelize.query(`
13
+ ALTER TABLE "field_policies"
14
+ DROP COLUMN IF EXISTS "entity_type"
15
+ `);
16
+ };
17
+
18
+ //#endregion
19
+ exports.down = down;
20
+ exports.up = up;
@@ -0,0 +1,18 @@
1
+ //#region src/migrations/005-add-entity-type-to-field-policies.ts
2
+ const up = async ({ context: queryInterface }) => {
3
+ const { sequelize } = queryInterface;
4
+ await sequelize.query(`
5
+ ALTER TABLE "field_policies"
6
+ ADD COLUMN IF NOT EXISTS "entity_type" VARCHAR
7
+ `);
8
+ };
9
+ const down = async ({ context: queryInterface }) => {
10
+ const { sequelize } = queryInterface;
11
+ await sequelize.query(`
12
+ ALTER TABLE "field_policies"
13
+ DROP COLUMN IF EXISTS "entity_type"
14
+ `);
15
+ };
16
+
17
+ //#endregion
18
+ export { down, up };
@@ -0,0 +1,94 @@
1
+ const require_index = require('../utils/logger/index.cjs');
2
+ const require_001_create_core_tables = require('./001-create-core-tables.cjs');
3
+ const require_002_create_custom_field_entries = require('./002-create-custom-field-entries.cjs');
4
+ const require_003_create_custom_field_model_type_map = require('./003-create-custom-field-model-type-map.cjs');
5
+ const require_004_create_field_policy_tables = require('./004-create-field-policy-tables.cjs');
6
+ const require_005_add_entity_type_to_field_policies = require('./005-add-entity-type-to-field-policies.cjs');
7
+
8
+ //#region src/migrations/index.ts
9
+ const { Umzug, SequelizeStorage } = require("umzug");
10
+ const buildMigrationList = (options) => {
11
+ const { useCustomFieldsEntries = false, useModelTypeMapping = false } = options;
12
+ return [
13
+ {
14
+ name: "001-create-core-tables",
15
+ up: require_001_create_core_tables.up,
16
+ down: require_001_create_core_tables.down
17
+ },
18
+ ...useCustomFieldsEntries ? [{
19
+ name: "002-create-custom-field-entries",
20
+ up: require_002_create_custom_field_entries.up,
21
+ down: require_002_create_custom_field_entries.down
22
+ }] : [],
23
+ ...useModelTypeMapping ? [{
24
+ name: "003-create-custom-field-model-type-map",
25
+ up: require_003_create_custom_field_model_type_map.up,
26
+ down: require_003_create_custom_field_model_type_map.down
27
+ }] : [],
28
+ {
29
+ name: "004-create-field-policy-tables",
30
+ up: require_004_create_field_policy_tables.up,
31
+ down: require_004_create_field_policy_tables.down
32
+ },
33
+ {
34
+ name: "005-add-entity-type-to-field-policies",
35
+ up: require_005_add_entity_type_to_field_policies.up,
36
+ down: require_005_add_entity_type_to_field_policies.down
37
+ }
38
+ ];
39
+ };
40
+ const SADOT_MIGRATION_LOCK_ID = 839274628;
41
+ /**
42
+ * Runs sadot migrations via umzug. All migrations use IF NOT EXISTS / IF EXISTS,
43
+ * so they are fully idempotent — safe to run against both fresh and existing
44
+ * databases (including DBs previously managed by the legacy sync() path).
45
+ *
46
+ * A PostgreSQL advisory lock is acquired before running migrations so that when
47
+ * multiple pods start concurrently only one of them executes the migrations.
48
+ * The remaining pods block until the lock is released, then proceed — Umzug will
49
+ * see the migrations have already been applied and skip them.
50
+ */
51
+ const runSadotMigrations = async (sequelize, options = {}) => {
52
+ const queryInterface = sequelize.getQueryInterface();
53
+ const storage = new SequelizeStorage({
54
+ sequelize,
55
+ tableName: "sadot_migrations"
56
+ });
57
+ const migrator = new Umzug({
58
+ migrations: buildMigrationList(options),
59
+ context: queryInterface,
60
+ storage,
61
+ logger: {
62
+ info: (msg) => require_index.default.info(`[sadot] ${JSON.stringify(msg)}`),
63
+ warn: (msg) => require_index.default.warn(`[sadot] ${JSON.stringify(msg)}`),
64
+ error: (msg) => require_index.default.error(`[sadot] ${JSON.stringify(msg)}`),
65
+ debug: (msg) => require_index.default.debug(`[sadot] ${JSON.stringify(msg)}`)
66
+ }
67
+ });
68
+ const pending = await migrator.pending();
69
+ if (pending.length === 0) {
70
+ require_index.default.info("[sadot] no pending migrations, skipping");
71
+ return;
72
+ }
73
+ require_index.default.info("[sadot] pending migrations detected", { pending: pending.map((m) => m.name) });
74
+ if ((sequelize.options?.pool?.max ?? 5) < 2) {
75
+ require_index.default.info("[sadot] connection pool too small for advisory lock, running migrations directly");
76
+ await migrator.up();
77
+ return;
78
+ }
79
+ require_index.default.info("[sadot] acquiring advisory lock");
80
+ const transaction = await sequelize.transaction();
81
+ try {
82
+ await sequelize.query(`SELECT pg_advisory_lock(${SADOT_MIGRATION_LOCK_ID})`, { transaction });
83
+ require_index.default.info("[sadot] advisory lock acquired");
84
+ if ((await migrator.pending()).length > 0) await migrator.up();
85
+ else require_index.default.info("[sadot] migrations already applied by another instance, skipping");
86
+ } finally {
87
+ await sequelize.query(`SELECT pg_advisory_unlock(${SADOT_MIGRATION_LOCK_ID})`, { transaction });
88
+ await transaction.commit();
89
+ require_index.default.info("[sadot] advisory lock released");
90
+ }
91
+ };
92
+
93
+ //#endregion
94
+ exports.runSadotMigrations = runSadotMigrations;