@mj-biz-apps/contracts-entities 0.1.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 (46) hide show
  1. package/LICENSE +183 -0
  2. package/dist/ContractEntity.d.ts +181 -0
  3. package/dist/ContractEntity.d.ts.map +1 -0
  4. package/dist/ContractEntity.js +261 -0
  5. package/dist/ContractEntity.js.map +1 -0
  6. package/dist/ContractTemplateEntity.d.ts +50 -0
  7. package/dist/ContractTemplateEntity.d.ts.map +1 -0
  8. package/dist/ContractTemplateEntity.js +85 -0
  9. package/dist/ContractTemplateEntity.js.map +1 -0
  10. package/dist/ContractTemplateModificationEntity.d.ts +46 -0
  11. package/dist/ContractTemplateModificationEntity.d.ts.map +1 -0
  12. package/dist/ContractTemplateModificationEntity.js +72 -0
  13. package/dist/ContractTemplateModificationEntity.js.map +1 -0
  14. package/dist/ContractTemplateProvisionEntity.d.ts +45 -0
  15. package/dist/ContractTemplateProvisionEntity.d.ts.map +1 -0
  16. package/dist/ContractTemplateProvisionEntity.js +73 -0
  17. package/dist/ContractTemplateProvisionEntity.js.map +1 -0
  18. package/dist/ContractTypeEntity.d.ts +55 -0
  19. package/dist/ContractTypeEntity.d.ts.map +1 -0
  20. package/dist/ContractTypeEntity.js +82 -0
  21. package/dist/ContractTypeEntity.js.map +1 -0
  22. package/dist/contract-state.d.ts +49 -0
  23. package/dist/contract-state.d.ts.map +1 -0
  24. package/dist/contract-state.js +48 -0
  25. package/dist/contract-state.js.map +1 -0
  26. package/dist/generated/entity_subclasses.d.ts +1235 -0
  27. package/dist/generated/entity_subclasses.d.ts.map +1 -0
  28. package/dist/generated/entity_subclasses.js +1817 -0
  29. package/dist/generated/entity_subclasses.js.map +1 -0
  30. package/dist/generated/remote_operations.d.ts +1145 -0
  31. package/dist/generated/remote_operations.d.ts.map +1 -0
  32. package/dist/generated/remote_operations.js +426 -0
  33. package/dist/generated/remote_operations.js.map +1 -0
  34. package/dist/index.d.ts +30 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +49 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/required-field-prose.d.ts +48 -0
  39. package/dist/required-field-prose.d.ts.map +1 -0
  40. package/dist/required-field-prose.js +55 -0
  41. package/dist/required-field-prose.js.map +1 -0
  42. package/dist/value-list-validation.d.ts +69 -0
  43. package/dist/value-list-validation.d.ts.map +1 -0
  44. package/dist/value-list-validation.js +88 -0
  45. package/dist/value-list-validation.js.map +1 -0
  46. package/package.json +33 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Swap the flat nullability prose for something actionable, and collapse duplicates, in place.
3
+ *
4
+ * WHY REPLACE AND NOT APPEND. One mistake must produce one error. Appending would leave the flat
5
+ * message beside the useful one, so a single empty field would mark itself twice.
6
+ *
7
+ * WHY COLLAPSE. A required field with a not-blank CHECK genuinely produces TWO absence errors on a
8
+ * create, and both are correct: MJ's nullability check refuses the null, and CodeGen's generated
9
+ * validator — derived from the CHECK — refuses null, empty AND whitespace, because the CHECK has to
10
+ * cover all three. Two rungs of the ladder saying the same thing about the same field; the user needs
11
+ * to be told once.
12
+ *
13
+ * WHY MATCH ON EMPTINESS RATHER THAN ON MJ'S WORDING. The obvious implementation greps the message
14
+ * text, which couples this to a string in MJ core it does not own and cannot see change. Matching on
15
+ * `Source` plus "the value really is absent" is stable across any rewording, and cannot capture the
16
+ * wrong error: the only other check MJ runs on these fields is `MaxLength`, which by construction
17
+ * fires only when a value is present.
18
+ *
19
+ * `result.Success` is deliberately not recomputed. Rewording cannot change a verdict, and collapsing
20
+ * cannot either — dropping a duplicate leaves at least one error standing for the same field.
21
+ */
22
+ export function ExplainMissingRequiredFields(entity, result, prose) {
23
+ const explained = new Set();
24
+ const kept = [];
25
+ for (const error of result.Errors) {
26
+ const source = error.Source ?? '';
27
+ const sentence = prose[source];
28
+ if (!sentence || !fieldIsAbsent(entity, source)) {
29
+ kept.push(error);
30
+ continue;
31
+ }
32
+ if (explained.has(source))
33
+ continue;
34
+ explained.add(source);
35
+ error.Message = sentence;
36
+ kept.push(error);
37
+ }
38
+ result.Errors = kept;
39
+ }
40
+ /**
41
+ * Whether the named field is genuinely empty — the condition MJ's nullability check fires on, plus the
42
+ * blank-string case, which is what the app's `…_TextNotBlank` CHECK constraints add.
43
+ *
44
+ * A field the entity does not have returns FALSE, not true. That direction matters: an unknown field
45
+ * name means a prose map has drifted from the schema, and rewording an error for a field that does not
46
+ * exist would hide the drift behind a friendly sentence.
47
+ */
48
+ function fieldIsAbsent(entity, fieldName) {
49
+ const field = entity.Fields.find((f) => f.EntityFieldInfo.Name === fieldName);
50
+ if (!field)
51
+ return false;
52
+ const value = field.Value;
53
+ return value === null || value === undefined || (typeof value === 'string' && value.trim().length === 0);
54
+ }
55
+ //# sourceMappingURL=required-field-prose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"required-field-prose.js","sourceRoot":"","sources":["../src/required-field-prose.ts"],"names":[],"mappings":"AA2BA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,4BAA4B,CAAC,MAAkB,EAAE,MAAwB,EAAE,KAAyB;IAChH,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,MAAM,IAAI,GAA0B,EAAE,CAAC;IAEvC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACjB,SAAS;QACb,CAAC;QACD,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS;QACpC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtB,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;AACzB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,MAAkB,EAAE,SAAiB;IACxD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAC9E,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,KAAK,GAAY,KAAK,CAAC,KAAK,CAAC;IACnC,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;AAC7G,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @fileoverview A STOPGAP for [MJ#3969](https://github.com/MemberJunction/MJ/issues/3969) — MJ does
3
+ * not validate value-list fields, so an `IN (…)` CHECK has no TypeScript counterpart at all.
4
+ *
5
+ * ## What is missing upstream
6
+ *
7
+ * When CodeGen meets `CHECK (Status IN ('Active','Inactive'))` it records the legal values as
8
+ * metadata — `EntityField.ValueListType = 'List'` plus `__mj.EntityFieldValue` rows — rather than
9
+ * emitting a generated `Validate()` method. That is the right call: the value list is also what the
10
+ * UI needs to render a dropdown, and one representation beats two.
11
+ *
12
+ * But `BaseEntity` then never reads it. `EntityField.Validate()` checks nullability, `MaxLength`,
13
+ * date parseability and numeric range, and stops. So this class of constraint is the one kind of
14
+ * schema rule with **no representation in TypeScript at all**: neither the browser nor a server
15
+ * subclass can preflight it, and an out-of-list value is refused only by SQL Server, as a raw
16
+ * constraint violation with no field attached.
17
+ *
18
+ * ## Why the dropdown is not the answer
19
+ *
20
+ * It protects the *form* path, which is presumably why nobody noticed. Every other path is
21
+ * unguarded — `mj sync push`, the GraphQL mutations, an Action, a subclass assigning the field in
22
+ * code, a data load — and those are precisely the paths where a typo is least likely to pass a human
23
+ * first.
24
+ *
25
+ * ## Why this is generic rather than three hand-written checks
26
+ *
27
+ * Three fields need it today (`ContractType.Status`, `ContractTemplateType.Status`,
28
+ * `ContractTemplateType.Status`). Naming them here would mean a fourth value-list field added next
29
+ * year is silently unguarded, and nothing would fail to say so. Driving off `ValueListTypeEnum`
30
+ * instead means the guard covers whatever the schema declares, now and later, and needs no edit when
31
+ * the schema changes — which is the same reason the rules it stands in for belong in MJ core.
32
+ *
33
+ * ## Deleting this
34
+ *
35
+ * When MJ#3969 lands, delete this file, drop the `ValidateValueLists(result)` call from every shared
36
+ * subclass, and delete `value-list-validation.test.ts`. Nothing else references it. The upstream fix
37
+ * produces the same errors from the same metadata, so the only observable change should be that the
38
+ * message is worded by MJ rather than by us.
39
+ *
40
+ * @module @mj-biz-apps/contracts-entities
41
+ */
42
+ import { BaseEntity, ValidationResult } from '@memberjunction/core';
43
+ /**
44
+ * Reject any value-list field whose value is not in its list.
45
+ *
46
+ * Call it from a shared subclass's `Validate()` override, after `super.Validate()`.
47
+ *
48
+ * Three exclusions, each of which would otherwise turn this from a guard into a bug:
49
+ *
50
+ * 1. **`List` only — never `ListOrUserEntry`.** That second mode exists precisely to allow values
51
+ * outside the list; validating it would reject the very thing it was chosen to permit.
52
+ * 2. **An empty value set validates nothing.** A field marked `List` whose `EntityFieldValue` rows
53
+ * have not been seeded would otherwise reject every value including the correct one, which is a
54
+ * far worse failure than the one this prevents.
55
+ * 3. **Null and empty are left alone.** Whether the field may be empty is the nullability check's
56
+ * question, and it has already answered it by the time this runs. Answering it again would report
57
+ * one mistake as two errors.
58
+ *
59
+ * Read-only and virtual fields are skipped for the same reason `EntityField.Validate()` skips them:
60
+ * the caller cannot set them, so refusing a save over one is a dead end with no fix available.
61
+ *
62
+ * The message lists the legal values rather than merely saying the value is invalid — a refusal that
63
+ * does not say what would have been accepted sends the user back to guess.
64
+ *
65
+ * @param entity - The record being validated.
66
+ * @param result - The accumulating result; errors are pushed onto it and `Success` cleared.
67
+ */
68
+ export declare function ValidateValueLists(entity: BaseEntity, result: ValidationResult): void;
69
+ //# sourceMappingURL=value-list-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-list-validation.d.ts","sourceRoot":"","sources":["../src/value-list-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,UAAU,EAAsE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExI;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAyBrF"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @fileoverview A STOPGAP for [MJ#3969](https://github.com/MemberJunction/MJ/issues/3969) — MJ does
3
+ * not validate value-list fields, so an `IN (…)` CHECK has no TypeScript counterpart at all.
4
+ *
5
+ * ## What is missing upstream
6
+ *
7
+ * When CodeGen meets `CHECK (Status IN ('Active','Inactive'))` it records the legal values as
8
+ * metadata — `EntityField.ValueListType = 'List'` plus `__mj.EntityFieldValue` rows — rather than
9
+ * emitting a generated `Validate()` method. That is the right call: the value list is also what the
10
+ * UI needs to render a dropdown, and one representation beats two.
11
+ *
12
+ * But `BaseEntity` then never reads it. `EntityField.Validate()` checks nullability, `MaxLength`,
13
+ * date parseability and numeric range, and stops. So this class of constraint is the one kind of
14
+ * schema rule with **no representation in TypeScript at all**: neither the browser nor a server
15
+ * subclass can preflight it, and an out-of-list value is refused only by SQL Server, as a raw
16
+ * constraint violation with no field attached.
17
+ *
18
+ * ## Why the dropdown is not the answer
19
+ *
20
+ * It protects the *form* path, which is presumably why nobody noticed. Every other path is
21
+ * unguarded — `mj sync push`, the GraphQL mutations, an Action, a subclass assigning the field in
22
+ * code, a data load — and those are precisely the paths where a typo is least likely to pass a human
23
+ * first.
24
+ *
25
+ * ## Why this is generic rather than three hand-written checks
26
+ *
27
+ * Three fields need it today (`ContractType.Status`, `ContractTemplateType.Status`,
28
+ * `ContractTemplateType.Status`). Naming them here would mean a fourth value-list field added next
29
+ * year is silently unguarded, and nothing would fail to say so. Driving off `ValueListTypeEnum`
30
+ * instead means the guard covers whatever the schema declares, now and later, and needs no edit when
31
+ * the schema changes — which is the same reason the rules it stands in for belong in MJ core.
32
+ *
33
+ * ## Deleting this
34
+ *
35
+ * When MJ#3969 lands, delete this file, drop the `ValidateValueLists(result)` call from every shared
36
+ * subclass, and delete `value-list-validation.test.ts`. Nothing else references it. The upstream fix
37
+ * produces the same errors from the same metadata, so the only observable change should be that the
38
+ * message is worded by MJ rather than by us.
39
+ *
40
+ * @module @mj-biz-apps/contracts-entities
41
+ */
42
+ import { EntityFieldValueListType, ValidationErrorInfo, ValidationErrorType } from '@memberjunction/core';
43
+ /**
44
+ * Reject any value-list field whose value is not in its list.
45
+ *
46
+ * Call it from a shared subclass's `Validate()` override, after `super.Validate()`.
47
+ *
48
+ * Three exclusions, each of which would otherwise turn this from a guard into a bug:
49
+ *
50
+ * 1. **`List` only — never `ListOrUserEntry`.** That second mode exists precisely to allow values
51
+ * outside the list; validating it would reject the very thing it was chosen to permit.
52
+ * 2. **An empty value set validates nothing.** A field marked `List` whose `EntityFieldValue` rows
53
+ * have not been seeded would otherwise reject every value including the correct one, which is a
54
+ * far worse failure than the one this prevents.
55
+ * 3. **Null and empty are left alone.** Whether the field may be empty is the nullability check's
56
+ * question, and it has already answered it by the time this runs. Answering it again would report
57
+ * one mistake as two errors.
58
+ *
59
+ * Read-only and virtual fields are skipped for the same reason `EntityField.Validate()` skips them:
60
+ * the caller cannot set them, so refusing a save over one is a dead end with no fix available.
61
+ *
62
+ * The message lists the legal values rather than merely saying the value is invalid — a refusal that
63
+ * does not say what would have been accepted sends the user back to guess.
64
+ *
65
+ * @param entity - The record being validated.
66
+ * @param result - The accumulating result; errors are pushed onto it and `Success` cleared.
67
+ */
68
+ export function ValidateValueLists(entity, result) {
69
+ for (const field of entity.Fields) {
70
+ const info = field.EntityFieldInfo;
71
+ if (info.ReadOnly || info.IsVirtual)
72
+ continue;
73
+ if (info.ValueListTypeEnum !== EntityFieldValueListType.List)
74
+ continue;
75
+ const allowed = info.EntityFieldValues;
76
+ if (!allowed || allowed.length === 0)
77
+ continue;
78
+ const value = field.Value;
79
+ if (value === null || value === undefined || value === '')
80
+ continue;
81
+ if (allowed.some((candidate) => candidate.Value === value))
82
+ continue;
83
+ result.Success = false;
84
+ result.Errors.push(new ValidationErrorInfo(info.Name, `${info.DisplayNameOrName} must be one of: ${allowed.map((candidate) => candidate.Value).join(', ')}. ` +
85
+ `"${String(value)}" is not one of them.`, value, ValidationErrorType.Failure));
86
+ }
87
+ }
88
+ //# sourceMappingURL=value-list-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-list-validation.js","sourceRoot":"","sources":["../src/value-list-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAc,wBAAwB,EAAE,mBAAmB,EAAE,mBAAmB,EAAoB,MAAM,sBAAsB,CAAC;AAExI;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAkB,EAAE,MAAwB;IAC3E,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,eAAe,CAAC;QACnC,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS;YAAE,SAAS;QAC9C,IAAI,IAAI,CAAC,iBAAiB,KAAK,wBAAwB,CAAC,IAAI;YAAE,SAAS;QAEvE,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,CAAC;QACvC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAE/C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC1B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;YAAE,SAAS;QAEpE,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,KAAK,KAAK,CAAC;YAAE,SAAS;QAErE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,MAAM,CAAC,MAAM,CAAC,IAAI,CACd,IAAI,mBAAmB,CACnB,IAAI,CAAC,IAAI,EACT,GAAG,IAAI,CAAC,iBAAiB,oBAAoB,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YACnG,IAAI,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAC5C,KAAK,EACL,mBAAmB,CAAC,OAAO,CAC9B,CACJ,CAAC;IACN,CAAC;AACL,CAAC"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@mj-biz-apps/contracts-entities",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Generated entity subclasses for the app schema. TODO(template): rename package + description.",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/MemberJunction/bizapps-contracts"
11
+ },
12
+ "license": "BUSL-1.1",
13
+ "dependencies": {
14
+ "zod": "^3.25.76"
15
+ },
16
+ "peerDependencies": {
17
+ "@memberjunction/core": "^6.1.0-edge.3",
18
+ "@memberjunction/global": "^6.1.0-edge.3"
19
+ },
20
+ "devDependencies": {
21
+ "typescript": "^5.9.3"
22
+ },
23
+ "files": [
24
+ "/dist"
25
+ ],
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "scripts": {
30
+ "build": "tsc && tsc-alias -f",
31
+ "test": "echo \"No tests configured yet\""
32
+ }
33
+ }