@oondemand/oon-core-back 0.3.45 → 0.3.47

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.
package/README.md CHANGED
@@ -21,6 +21,15 @@ Compatibilidade temporária: `CENTRAL_ATIVACAO_BACKEND_URL` e `MEUS_APPS_BACKEND
21
21
 
22
22
  Campos adicionais podem ser declarados em `activation.fields`; `password` e `secret` são sanitizados na configuração retornada ao frontend. Hooks opcionais: `validate`, `beforeComplete`, `afterComplete`.
23
23
 
24
+ ## Imagem de entrega
25
+
26
+ O comando de delivery preserva `central.app.json` em dois pontos da imagem:
27
+
28
+ - `/src/central.app.json` durante o build do frontend declarativo;
29
+ - `/app/central.app.json` para descoberta pelo backend em runtime.
30
+
31
+ Centrais legadas sem o manifesto continuam suportadas. O empacotador cria uma pasta intermediária vazia, evitando tornar `central.app.json` obrigatório para aplicações que ainda usam somente `central.config.js`.
32
+
24
33
  ## Rótulos de campos relacionados
25
34
 
26
35
  Por padrão, campos declarados com `fields.ref(...)` continuam sendo devolvidos pelo CRUD como `ObjectId`. Uma model pode optar pela população segura das referências usadas em grids e cards:
@@ -38,4 +47,4 @@ defineModel({
38
47
  });
39
48
  ```
40
49
 
41
- Use `populateRefs: true` para todas as referências da model ou informe uma lista explícita. O CRUD devolve somente `_id` e campos usuais de identificação, como nome, razão social, descrição, código, e-mail e campos pesquisáveis da model referenciada. Exportações mantêm os identificadores originais.
50
+ Use `populateRefs: true` para todas as referências da model ou informe uma lista explícita. O CRUD devolve somente `_id` e campos usuais de identificação, como nome, razão social, descrição, código, e-mail e campos pesquisáveis da model referenciada. Exportações mantêm os identificadores originais.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oondemand/oon-core-back",
3
- "version": "0.3.45",
3
+ "version": "0.3.47",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/oondemand/oon-platform.git",
@@ -11,6 +11,10 @@ const {
11
11
  DOMAIN_MANIFEST_FILENAME,
12
12
  loadDomainManifest,
13
13
  } = require("../manifest/domainManifest");
14
+ const {
15
+ PROCESS_MANIFEST_FILENAME,
16
+ loadProcessManifest,
17
+ } = require("../manifest/processManifest");
14
18
 
15
19
  const DOMAIN_DIRS = [
16
20
  "models",
@@ -76,6 +80,11 @@ function loadCentral(cwd = process.cwd()) {
76
80
  loadDomainManifest(domainManifestPath);
77
81
  }
78
82
 
83
+ const processManifestPath = path.join(cwd, PROCESS_MANIFEST_FILENAME);
84
+ if (fs.existsSync(processManifestPath)) {
85
+ loadProcessManifest(processManifestPath);
86
+ }
87
+
79
88
  const srcDir = path.join(cwd, "src");
80
89
  for (const dir of DOMAIN_DIRS) {
81
90
  const full = path.join(srcDir, dir);
@@ -93,4 +102,9 @@ function requireDir(dir) {
93
102
  }
94
103
  }
95
104
 
96
- module.exports = { loadCentral, DOMAIN_DIRS, APP_CONFIG_KEYS, assertConfigBoundary };
105
+ module.exports = {
106
+ loadCentral,
107
+ DOMAIN_DIRS,
108
+ APP_CONFIG_KEYS,
109
+ assertConfigBoundary,
110
+ };
@@ -7,10 +7,6 @@ const auth = require("./middlewares/auth");
7
7
  const { rbac } = require("./middlewares/rbac");
8
8
  const { mutationAudit } = require("./middlewares/mutationAudit");
9
9
 
10
- /**
11
- * Constrói o schema Mongoose a partir dos descriptors de `fields`,
12
- * separando o bloco `__meta` (consumido apenas por /core/metadata).
13
- */
14
10
  function buildSchema(schemaDef, options = {}) {
15
11
  const mongooseShape = {};
16
12
  const metaFields = {};
@@ -23,12 +19,19 @@ function buildSchema(schemaDef, options = {}) {
23
19
  metaFields[key] = { name: key, ...__meta };
24
20
  if (__meta.kind === "string" && __meta.searchable) searchableFields.push(key);
25
21
  } else {
26
- // Descriptor cru (compatível com Mongoose puro).
27
22
  mongooseShape[key] = descriptor;
28
23
  metaFields[key] = { name: key, kind: "raw" };
29
24
  }
30
25
  }
31
26
 
27
+ if (!Object.prototype.hasOwnProperty.call(mongooseShape, "__oonInvariantVersion")) {
28
+ mongooseShape.__oonInvariantVersion = {
29
+ type: Number,
30
+ default: 0,
31
+ select: false,
32
+ };
33
+ }
34
+
32
35
  const schema = new mongoose.Schema(mongooseShape, {
33
36
  timestamps: true,
34
37
  ...options,
@@ -37,10 +40,6 @@ function buildSchema(schemaDef, options = {}) {
37
40
  return { schema, metaFields, searchableFields };
38
41
  }
39
42
 
40
- /**
41
- * defineModel — registra a model e gera derivações automáticas
42
- * (schema, CRUD, RBAC, paginação, validação, auditoria, metadata).
43
- */
44
43
  function defineModel(definition) {
45
44
  if (!definition?.name) throw new Error("defineModel requer `name`.");
46
45
  if (!definition?.schema) throw new Error(`defineModel("${definition.name}") requer \`schema\`.`);
@@ -50,7 +49,6 @@ function defineModel(definition) {
50
49
  definition.options
51
50
  );
52
51
 
53
- // Hooks de domínio (defineTrigger) ligados ao ciclo do documento.
54
52
  schema.pre("save", async function (next) {
55
53
  try {
56
54
  const { before } = registry.getTriggers(definition.name);
@@ -77,7 +75,6 @@ function defineModel(definition) {
77
75
  searchableFields,
78
76
  });
79
77
 
80
- // Permissões/actions derivadas para o front.
81
78
  if (definition.crud?.enabled !== false) {
82
79
  registry.registerFeature(definition.name, {
83
80
  model: definition.name,
@@ -89,10 +86,6 @@ function defineModel(definition) {
89
86
  return entry;
90
87
  }
91
88
 
92
- /**
93
- * defineCentral — declara metadados da Central (módulos ativos + paths de
94
- * domínio). Mescla na config de runtime.
95
- */
96
89
  function defineCentral(config = {}) {
97
90
  ctx.setConfig(config);
98
91
  return ctx.config;
@@ -122,11 +115,6 @@ function defineOmieMapping(name, config) {
122
115
  return registry.registerOmieMapping(name, { name, ...config });
123
116
  }
124
117
 
125
- /**
126
- * defineRoutes — rotas customizadas com o contrato de segurança do Core.
127
- * Entrega `router.private.*` (auth + RBAC + mutationAudit) e
128
- * `router.public.*`. NUNCA expõe `express.Router()` cru.
129
- */
130
118
  function defineRoutes(basePath, builder) {
131
119
  const expressRouter = express.Router();
132
120
 
@@ -168,4 +156,4 @@ module.exports = {
168
156
  definePipeline,
169
157
  defineOmieMapping,
170
158
  defineRoutes,
171
- };
159
+ };
@@ -1,14 +1,14 @@
1
1
  const Helpers = require("../utils/helpers");
2
2
  const registry = require("../registry");
3
- const { applyDomainMutation } = require("../../manifest/domainRules");
4
-
5
- function toPlainRecord(record) {
6
- if (!record || typeof record !== "object") return {};
7
- if (typeof record.toObject === "function") {
8
- return record.toObject({ depopulate: true });
9
- }
10
- return { ...record };
11
- }
3
+ const {
4
+ prepareProcessMutation,
5
+ assertAtomicInvariants,
6
+ assertDeleteAllowed,
7
+ withProcessTransaction,
8
+ recalculateDependents,
9
+ toPlainRecord,
10
+ } = require("../../manifest/processRuntime");
11
+ const { assertReferencePolicies } = require("../../manifest/referencePolicies");
12
12
 
13
13
  function hasDomainRules(entry) {
14
14
  const rules = entry?.definition?.domainRules;
@@ -20,28 +20,31 @@ function hasDomainRules(entry) {
20
20
  );
21
21
  }
22
22
 
23
- /**
24
- * Controllers HTTP de CRUD ligados a um service. Aplica regras declarativas do
25
- * manifesto e validações registradas via `defineValidation` antes de persistir.
26
- *
27
- * Atualizações podem chegar parcialmente pelo formulário em abas ou pelo
28
- * datagrid. Nesses casos, fórmulas e validações recebem o registro consolidado,
29
- * enquanto o service persiste somente os campos enviados e calculados.
30
- */
23
+ function hasProcessRules(entry) {
24
+ const rules = entry?.definition?.processRules;
25
+ return Boolean(
26
+ rules
27
+ && (rules.workflow
28
+ || (rules.bindings || []).length
29
+ || (rules.references || []).length
30
+ || (rules.deleteProtection || []).length
31
+ || (rules.atomicInvariants || []).length),
32
+ );
33
+ }
34
+
31
35
  function createCrudController(entry, service) {
32
36
  const runCustomValidation = async (data, context) => {
33
37
  const validate = registry.getValidation(entry.name);
34
38
  if (validate) await validate(data, context);
35
39
  };
36
40
 
37
- const prepareCreate = async (data, method = "post") => {
38
- const prepared = applyDomainMutation({
39
- rules: entry.definition?.domainRules,
40
- current: null,
41
- changes: data,
41
+ const prepareCreate = async (data, method = "post", session = null) => {
42
+ const prepared = await prepareProcessMutation(entry, {}, data, {
42
43
  op: "create",
44
+ session,
43
45
  });
44
46
 
47
+ await assertReferencePolicies(entry, prepared.consolidated, { session });
45
48
  await runCustomValidation(prepared.consolidated, {
46
49
  op: "create",
47
50
  method,
@@ -49,31 +52,33 @@ function createCrudController(entry, service) {
49
52
  requestedChanges: prepared.requestedChanges,
50
53
  changes: prepared.changes,
51
54
  consolidated: prepared.consolidated,
55
+ changedFields: prepared.changedFields,
56
+ session,
52
57
  });
53
58
  return prepared;
54
59
  };
55
60
 
56
- const prepareUpdate = async (id, changes, method) => {
61
+ const prepareUpdate = async (id, changes, method, session = null) => {
57
62
  const validate = registry.getValidation(entry.name);
58
- if (!validate && !hasDomainRules(entry)) {
63
+ if (!validate && !hasDomainRules(entry) && !hasProcessRules(entry)) {
59
64
  const normalizedChanges = changes && typeof changes === "object" ? { ...changes } : {};
60
65
  return {
61
66
  current: null,
62
67
  requestedChanges: normalizedChanges,
63
68
  changes: normalizedChanges,
64
69
  consolidated: normalizedChanges,
70
+ changedFields: Object.keys(normalizedChanges),
65
71
  };
66
72
  }
67
73
 
68
- const currentRecord = await service.getById(id);
74
+ const currentRecord = await service.getById(id, { session });
69
75
  const current = toPlainRecord(currentRecord);
70
- const prepared = applyDomainMutation({
71
- rules: entry.definition?.domainRules,
72
- current,
73
- changes,
76
+ const prepared = await prepareProcessMutation(entry, current, changes, {
74
77
  op: "update",
78
+ session,
75
79
  });
76
80
 
81
+ await assertReferencePolicies(entry, prepared.consolidated, { session });
77
82
  if (validate) {
78
83
  await validate(prepared.consolidated, {
79
84
  op: "update",
@@ -83,12 +88,36 @@ function createCrudController(entry, service) {
83
88
  requestedChanges: prepared.requestedChanges,
84
89
  changes: prepared.changes,
85
90
  consolidated: prepared.consolidated,
91
+ changedFields: prepared.changedFields,
92
+ session,
86
93
  });
87
94
  }
88
95
 
89
96
  return { current, ...prepared };
90
97
  };
91
98
 
99
+ async function createOne(data, method, session) {
100
+ const prepared = await prepareCreate(data, method, session);
101
+ await assertAtomicInvariants(entry, prepared.consolidated, null, session);
102
+ const record = await service.create(prepared.changes, { session });
103
+ await recalculateDependents(entry, null, toPlainRecord(record), {
104
+ session,
105
+ changedFields: prepared.changedFields,
106
+ });
107
+ return record;
108
+ }
109
+
110
+ async function updateOne(id, changes, method, session) {
111
+ const prepared = await prepareUpdate(id, changes, method, session);
112
+ await assertAtomicInvariants(entry, prepared.consolidated, prepared.current, session);
113
+ const record = await service.update(id, prepared.changes, { session });
114
+ await recalculateDependents(entry, prepared.current, toPlainRecord(record), {
115
+ session,
116
+ changedFields: prepared.changedFields,
117
+ });
118
+ return record;
119
+ }
120
+
92
121
  return {
93
122
  async list(req, res) {
94
123
  const { pageIndex, pageSize, searchTerm, sort, ...filtros } = req.query;
@@ -108,35 +137,69 @@ function createCrudController(entry, service) {
108
137
  },
109
138
 
110
139
  async create(req, res) {
111
- const prepared = await prepareCreate(req.body ?? {}, "post");
112
- const registro = await service.create(prepared.changes);
140
+ const registro = await withProcessTransaction(
141
+ entry,
142
+ (session) => createOne(req.body ?? {}, "post", session),
143
+ );
113
144
  Helpers.sendResponse({ res, statusCode: 201, [entry.singular]: registro });
114
145
  },
115
146
 
116
147
  async update(req, res) {
117
- const prepared = await prepareUpdate(req.params.id, req.body ?? {}, "put");
118
- const registro = await service.update(req.params.id, prepared.changes);
148
+ const registro = await withProcessTransaction(
149
+ entry,
150
+ (session) => updateOne(req.params.id, req.body ?? {}, "put", session),
151
+ );
119
152
  Helpers.sendResponse({ res, statusCode: 200, [entry.singular]: registro });
120
153
  },
121
154
 
122
155
  async patch(req, res) {
123
- const prepared = await prepareUpdate(req.params.id, req.body ?? {}, "patch");
124
- const registro = await service.update(req.params.id, prepared.changes);
156
+ const registro = await withProcessTransaction(
157
+ entry,
158
+ (session) => updateOne(req.params.id, req.body ?? {}, "patch", session),
159
+ );
125
160
  Helpers.sendResponse({ res, statusCode: 200, [entry.singular]: registro });
126
161
  },
127
162
 
128
163
  async remove(req, res) {
129
- const registro = await service.remove(req.params.id);
164
+ const registro = await withProcessTransaction(entry, async (session) => {
165
+ const currentRecord = await service.getById(req.params.id, { session });
166
+ const current = toPlainRecord(currentRecord);
167
+ await assertDeleteAllowed(entry, req.params.id, { session });
168
+ const removed = await service.remove(req.params.id, { session });
169
+ await recalculateDependents(entry, current, null, {
170
+ session,
171
+ changedFields: Object.keys(current),
172
+ });
173
+ return removed;
174
+ });
130
175
  Helpers.sendResponse({ res, statusCode: 200, [entry.singular]: registro });
131
176
  },
132
177
 
133
178
  async importMany(req, res) {
134
179
  const rows = req.body?.rows || req.body;
135
- const preparedRows = Array.isArray(rows)
136
- ? await Promise.all(rows.map(async (row) => (await prepareCreate(row, "import")).changes))
137
- : rows;
138
- const result = await service.importMany(preparedRows);
139
- Helpers.sendResponse({ res, statusCode: 201, ...result });
180
+ if (!Array.isArray(rows)) {
181
+ const result = await service.importMany(rows);
182
+ Helpers.sendResponse({ res, statusCode: 201, ...result });
183
+ return;
184
+ }
185
+
186
+ if (!hasProcessRules(entry)) {
187
+ const preparedRows = await Promise.all(
188
+ rows.map(async (row) => (await prepareCreate(row, "import")).changes),
189
+ );
190
+ const result = await service.importMany(preparedRows);
191
+ Helpers.sendResponse({ res, statusCode: 201, ...result });
192
+ return;
193
+ }
194
+
195
+ let inserted = 0;
196
+ for (const row of rows) {
197
+ await withProcessTransaction(entry, async (session) => {
198
+ await createOne(row, "import", session);
199
+ inserted += 1;
200
+ });
201
+ }
202
+ Helpers.sendResponse({ res, statusCode: 201, inserted });
140
203
  },
141
204
 
142
205
  async exportAll(req, res) {
@@ -146,4 +209,9 @@ function createCrudController(entry, service) {
146
209
  };
147
210
  }
148
211
 
149
- module.exports = { createCrudController, toPlainRecord, hasDomainRules };
212
+ module.exports = {
213
+ createCrudController,
214
+ toPlainRecord,
215
+ hasDomainRules,
216
+ hasProcessRules,
217
+ };
@@ -15,11 +15,6 @@ const COMMON_REFERENCE_LABEL_FIELDS = [
15
15
  "sigla",
16
16
  ];
17
17
 
18
- /**
19
- * Gera especificações de populate somente quando a model opta explicitamente
20
- * por `crud.populateRefs`. O select é restrito a campos de identificação para
21
- * evitar devolver o documento relacionado inteiro nas listagens genéricas.
22
- */
23
18
  function referencePopulateSpecs(entry) {
24
19
  const setting = entry.definition?.crud?.populateRefs;
25
20
  if (!setting) return [];
@@ -52,10 +47,6 @@ function populateQuery(query, specs) {
52
47
  return specs.length ? query.populate(specs) : query;
53
48
  }
54
49
 
55
- /**
56
- * Aceita tanto uma Query Mongoose quanto uma Promise/Document devolvida por
57
- * uma model que sobrescreveu métodos como `findByIdAndUpdate`.
58
- */
59
50
  async function resolvePopulated(result, specs) {
60
51
  if (!specs.length) return result;
61
52
  if (result && typeof result.populate === "function") {
@@ -67,10 +58,10 @@ async function resolvePopulated(result, specs) {
67
58
  return doc;
68
59
  }
69
60
 
70
- /**
71
- * Gera um service de CRUD genérico para uma model registrada.
72
- * Cobre paginação, filtros, busca textual, ordenação, import e export.
73
- */
61
+ function withSession(query, session) {
62
+ return session && query && typeof query.session === "function" ? query.session(session) : query;
63
+ }
64
+
74
65
  function createCrudService(entry) {
75
66
  const { mongooseModel: Model, searchableFields } = entry;
76
67
  const populateSpecs = referencePopulateSpecs(entry);
@@ -106,40 +97,44 @@ function createCrudService(entry) {
106
97
  };
107
98
  }
108
99
 
109
- async function getById(id) {
110
- const doc = await resolvePopulated(Model.findById(id), populateSpecs);
100
+ async function getById(id, options = {}) {
101
+ const query = withSession(Model.findById(id), options.session);
102
+ const doc = await resolvePopulated(query, populateSpecs);
111
103
  if (!doc) throw new GenericError("Registro não encontrado.", { statusCode: 404 });
112
104
  return doc;
113
105
  }
114
106
 
115
- async function create(data) {
116
- const doc = await Model.create(data);
107
+ async function create(data, options = {}) {
108
+ const doc = new Model(data);
109
+ await doc.save({ session: options.session || undefined });
117
110
  return resolvePopulated(doc, populateSpecs);
118
111
  }
119
112
 
120
- async function update(id, data) {
121
- const doc = await resolvePopulated(
122
- Model.findByIdAndUpdate(id, data, {
123
- new: true,
124
- runValidators: true,
125
- }),
126
- populateSpecs
127
- );
113
+ async function update(id, data, options = {}) {
114
+ const query = Model.findByIdAndUpdate(id, data, {
115
+ new: true,
116
+ runValidators: true,
117
+ session: options.session || undefined,
118
+ });
119
+ const doc = await resolvePopulated(query, populateSpecs);
128
120
  if (!doc) throw new GenericError("Registro não encontrado.", { statusCode: 404 });
129
121
  return doc;
130
122
  }
131
123
 
132
- async function remove(id) {
133
- const doc = await Model.findByIdAndDelete(id);
124
+ async function remove(id, options = {}) {
125
+ const doc = await withSession(Model.findByIdAndDelete(id), options.session);
134
126
  if (!doc) throw new GenericError("Registro não encontrado.", { statusCode: 404 });
135
127
  return doc;
136
128
  }
137
129
 
138
- async function importMany(rows = []) {
130
+ async function importMany(rows = [], options = {}) {
139
131
  if (!Array.isArray(rows)) {
140
132
  throw new GenericError("Esperado um array de registros.", { statusCode: 400 });
141
133
  }
142
- const docs = await Model.insertMany(rows, { ordered: false });
134
+ const docs = await Model.insertMany(rows, {
135
+ ordered: false,
136
+ session: options.session || undefined,
137
+ });
143
138
  return { inserted: docs.length };
144
139
  }
145
140
 
@@ -160,7 +155,6 @@ function cleanFilters(filtros) {
160
155
 
161
156
  function parseSort(sort) {
162
157
  if (!sort) return { createdAt: -1 };
163
- // "campo:asc" | "campo:desc" | "campo"
164
158
  const [field, dir] = String(sort).split(":");
165
159
  return { [field]: dir === "asc" ? 1 : -1 };
166
160
  }
@@ -10,6 +10,7 @@ WORKDIR /src/frontend
10
10
  COPY frontend/package*.json ./
11
11
  RUN if [ -f package-lock.json ]; then npm ci; else npm install; fi
12
12
  COPY frontend/ ./
13
+ COPY .oon-delivery/app-manifest/ /src/
13
14
  ARG VITE_API_URL=/api
14
15
  ENV VITE_API_URL=$VITE_API_URL
15
16
  RUN npm run build
@@ -25,6 +26,7 @@ RUN apk add --no-cache nginx curl
25
26
  WORKDIR /app
26
27
  ENV NODE_ENV=production
27
28
  COPY --from=backend /app/backend /app/backend
29
+ COPY .oon-delivery/app-manifest/ /app/
28
30
  COPY --from=frontend /src/frontend/dist /usr/share/nginx/html
29
31
  COPY .oon-delivery/nginx.conf /etc/nginx/http.d/default.conf
30
32
  COPY .oon-delivery/entrypoint.sh /entrypoint.sh
@@ -60,9 +62,25 @@ trap 'kill $backend_pid 2>/dev/null || true' TERM INT EXIT
60
62
  exec nginx -g 'daemon off;'
61
63
  `;
62
64
 
65
+ function prepareAppManifest(workspace, deliveryDirectory) {
66
+ const manifestDirectory = path.join(deliveryDirectory, "app-manifest");
67
+ const manifestSource = path.join(workspace, "central.app.json");
68
+ const manifestTarget = path.join(manifestDirectory, "central.app.json");
69
+
70
+ fs.rmSync(manifestDirectory, { recursive: true, force: true });
71
+ fs.mkdirSync(manifestDirectory, { recursive: true });
72
+
73
+ if (fs.existsSync(manifestSource)) {
74
+ fs.copyFileSync(manifestSource, manifestTarget);
75
+ }
76
+
77
+ return manifestTarget;
78
+ }
79
+
63
80
  function prepareDeliveryFiles(workspace) {
64
81
  const target = path.join(workspace, ".oon-delivery");
65
82
  fs.mkdirSync(target, { recursive: true });
83
+ prepareAppManifest(workspace, target);
66
84
  fs.writeFileSync(path.join(target, "Dockerfile"), DOCKERFILE);
67
85
  fs.writeFileSync(path.join(target, "nginx.conf"), NGINX);
68
86
  fs.writeFileSync(path.join(target, "entrypoint.sh"), ENTRYPOINT, {
@@ -82,6 +100,7 @@ module.exports = {
82
100
  DOCKERFILE,
83
101
  NGINX,
84
102
  ENTRYPOINT,
103
+ prepareAppManifest,
85
104
  prepareDeliveryFiles,
86
105
  buildImage,
87
106
  };
package/src/index.js CHANGED
@@ -11,6 +11,9 @@ const { omie } = require("./modules/omie");
11
11
  const appManifest = require("./manifest/appManifest");
12
12
  const domainManifest = require("./manifest/domainManifest");
13
13
  const domainRules = require("./manifest/domainRules");
14
+ const processManifest = require("./manifest/processManifest");
15
+ const processRuntime = require("./manifest/processRuntime");
16
+ const referencePolicies = require("./manifest/referencePolicies");
14
17
 
15
18
  module.exports = {
16
19
  start,
@@ -49,9 +52,25 @@ module.exports = {
49
52
  loadDomainManifest: domainManifest.loadDomainManifest,
50
53
  evaluateDomainExpression: domainRules.evaluateDomainExpression,
51
54
  applyDomainMutation: domainRules.applyDomainMutation,
55
+ validateDomainRecord: domainRules.validateDomainRecord,
56
+ detectChangedFields: domainRules.detectChangedFields,
57
+
58
+ PROCESS_MANIFEST_FILENAME: processManifest.PROCESS_MANIFEST_FILENAME,
59
+ PROCESS_MANIFEST_SCHEMA_VERSION: processManifest.PROCESS_MANIFEST_SCHEMA_VERSION,
60
+ ProcessManifestError: processManifest.ProcessManifestError,
61
+ validateProcessManifest: processManifest.validateProcessManifest,
62
+ registerProcessManifest: processManifest.registerProcessManifest,
63
+ loadProcessManifest: processManifest.loadProcessManifest,
64
+ prepareProcessMutation: processRuntime.prepareProcessMutation,
65
+ resolveProcessBindings: processRuntime.resolveBindingsForRecords,
66
+ assertReferencePolicies: referencePolicies.assertReferencePolicies,
67
+ assertAtomicInvariants: processRuntime.assertAtomicInvariants,
68
+ assertDeleteAllowed: processRuntime.assertDeleteAllowed,
69
+ recalculateDependents: processRuntime.recalculateDependents,
70
+ drainProcessJobs: processRuntime.drainProcessJobs,
52
71
 
53
72
  fields,
54
73
  omie,
55
74
  GenericError,
56
75
  registry,
57
- };
76
+ };