@memberjunction/actions-base 5.51.0 → 6.1.0-edge.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 (34) hide show
  1. package/LICENSE +7 -0
  2. package/dist/ActionEngine-Base.d.ts +50 -1
  3. package/dist/ActionEngine-Base.d.ts.map +1 -1
  4. package/dist/ActionEngine-Base.js +15 -0
  5. package/dist/ActionEngine-Base.js.map +1 -1
  6. package/dist/EntityActionEngine-Base.d.ts +20 -0
  7. package/dist/EntityActionEngine-Base.d.ts.map +1 -1
  8. package/dist/EntityActionEngine-Base.js +31 -2
  9. package/dist/EntityActionEngine-Base.js.map +1 -1
  10. package/dist/EntityActionScopeResolver.d.ts +93 -0
  11. package/dist/EntityActionScopeResolver.d.ts.map +1 -0
  12. package/dist/EntityActionScopeResolver.js +145 -0
  13. package/dist/EntityActionScopeResolver.js.map +1 -0
  14. package/dist/ParamRedaction.d.ts +97 -0
  15. package/dist/ParamRedaction.d.ts.map +1 -0
  16. package/dist/ParamRedaction.js +142 -0
  17. package/dist/ParamRedaction.js.map +1 -0
  18. package/dist/__tests__/EntityActionEngine-Base.test.d.ts +2 -0
  19. package/dist/__tests__/EntityActionEngine-Base.test.d.ts.map +1 -0
  20. package/dist/__tests__/EntityActionEngine-Base.test.js +160 -0
  21. package/dist/__tests__/EntityActionEngine-Base.test.js.map +1 -0
  22. package/dist/__tests__/EntityActionScopeResolver.test.d.ts +2 -0
  23. package/dist/__tests__/EntityActionScopeResolver.test.d.ts.map +1 -0
  24. package/dist/__tests__/EntityActionScopeResolver.test.js +149 -0
  25. package/dist/__tests__/EntityActionScopeResolver.test.js.map +1 -0
  26. package/dist/__tests__/ParamRedaction.test.d.ts +2 -0
  27. package/dist/__tests__/ParamRedaction.test.d.ts.map +1 -0
  28. package/dist/__tests__/ParamRedaction.test.js +190 -0
  29. package/dist/__tests__/ParamRedaction.test.js.map +1 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +2 -0
  33. package/dist/index.js.map +1 -1
  34. package/package.json +12 -12
@@ -0,0 +1,142 @@
1
+ import { BaseEntity } from "@memberjunction/core";
2
+ import { UUIDsEqual } from "@memberjunction/global";
3
+ /**
4
+ * Upper bound on how many top-level key names a redaction record carries. A wide
5
+ * record would otherwise reintroduce the size problem the redaction exists to solve.
6
+ */
7
+ export const MAX_REDACTED_KEYS = 25;
8
+ /** The Entity Action `ValueType` values that pass a whole record and are therefore never logged. */
9
+ const WHOLE_RECORD_VALUE_TYPES = new Set(['entity object', 'entity object data']);
10
+ /** True when a redaction record (rather than a live parameter) is what's in hand. */
11
+ export function IsRedactedParam(param) {
12
+ return param.Logged === false;
13
+ }
14
+ /**
15
+ * Produces the persistable form of an action's parameters, applying the three
16
+ * redaction rules documented on this module.
17
+ *
18
+ * @param params The runtime parameters, as passed to (or returned by) the action.
19
+ * @param actionParams The `ActionParam` definition rows for the action. When a
20
+ * runtime parameter has no matching definition its value is logged —
21
+ * `ActionParam.LogValue` defaults to `1`, and an undeclared parameter has
22
+ * no declaration to opt out with. Rule 1 does not depend on this lookup.
23
+ * @param entityActionParams The `EntityActionParam` binding rows, when the run
24
+ * originated from an Entity Action. Omitted for direct invocations, in
25
+ * which case rules 1 and 2 cannot apply.
26
+ */
27
+ export function RedactParams(params, actionParams, entityActionParams) {
28
+ if (!params) {
29
+ return [];
30
+ }
31
+ return params.map(p => {
32
+ const definition = findDefinition(p.Name, actionParams);
33
+ const binding = findBinding(definition, entityActionParams);
34
+ const reason = resolveRedactionReason(definition, binding);
35
+ if (!reason) {
36
+ return p;
37
+ }
38
+ return buildRedactionRecord(p, binding, reason);
39
+ });
40
+ }
41
+ /**
42
+ * Convenience wrapper producing the JSON string persisters actually write. Kept
43
+ * beside {@link RedactParams} so no caller is tempted to `JSON.stringify` a raw
44
+ * `ActionParam[]` itself.
45
+ */
46
+ export function RedactParamsToJSON(params, actionParams, entityActionParams) {
47
+ return JSON.stringify(RedactParams(params, actionParams, entityActionParams));
48
+ }
49
+ /** Case-insensitive lookup of a runtime parameter's definition row. */
50
+ function findDefinition(name, actionParams) {
51
+ if (!actionParams || !name) {
52
+ return undefined;
53
+ }
54
+ const target = name.trim().toLowerCase();
55
+ return actionParams.find(ap => (ap.Name ?? '').trim().toLowerCase() === target);
56
+ }
57
+ /** Finds the Entity Action binding row that supplies this parameter, if the run came from a binding. */
58
+ function findBinding(definition, entityActionParams) {
59
+ if (!definition || !entityActionParams) {
60
+ return undefined;
61
+ }
62
+ return entityActionParams.find(eap => UUIDsEqual(eap.ActionParamID, definition.ID));
63
+ }
64
+ /**
65
+ * Applies the three rules in precedence order and returns the reason a value is
66
+ * withheld, or `undefined` when it may be logged.
67
+ */
68
+ function resolveRedactionReason(definition, binding) {
69
+ // Rule 1 — whole-record value types. Unconditional; nothing below can re-enable it.
70
+ if (binding && WHOLE_RECORD_VALUE_TYPES.has((binding.ValueType ?? '').trim().toLowerCase())) {
71
+ return 'WholeRecordValueType';
72
+ }
73
+ // Rule 2 — the binding's explicit override. NULL falls through to the definition.
74
+ if (binding && binding.LogValue != null) {
75
+ return binding.LogValue ? undefined : 'BindingLogValueFalse';
76
+ }
77
+ // Rule 3 — the definition. An absent definition means an undeclared parameter,
78
+ // which has nothing to opt out with, so it is logged (LogValue's default is 1).
79
+ if (definition && definition.LogValue === false) {
80
+ return 'ParamLogValueFalse';
81
+ }
82
+ return undefined;
83
+ }
84
+ /** Builds the shape-only record persisted in place of a suppressed value. */
85
+ function buildRedactionRecord(param, binding, reason) {
86
+ const record = {
87
+ Name: param.Name,
88
+ Type: param.Type,
89
+ Logged: false,
90
+ Reason: reason,
91
+ ByteLength: 0
92
+ };
93
+ if (binding?.ValueType) {
94
+ record.ValueType = binding.ValueType;
95
+ }
96
+ describeShape(param.Value, record);
97
+ return record;
98
+ }
99
+ /**
100
+ * Fills the shape fields of a redaction record. A `BaseEntity` is described
101
+ * through `GetAll()` — its fields are getters, not enumerable own properties, so
102
+ * describing the instance directly would report a misleading empty shape (the
103
+ * same trap `'Entity Object Data'` exists to avoid).
104
+ */
105
+ function describeShape(value, record) {
106
+ if (value === null || value === undefined) {
107
+ record.ByteLength = 0;
108
+ return;
109
+ }
110
+ const described = value instanceof BaseEntity ? value.GetAll() : value;
111
+ record.ByteLength = utf8ByteLength(described);
112
+ if (Array.isArray(described)) {
113
+ record.ItemCount = described.length;
114
+ return;
115
+ }
116
+ if (typeof described === 'object') {
117
+ const keys = Object.keys(described);
118
+ record.KeyCount = keys.length;
119
+ record.Keys = keys.slice(0, MAX_REDACTED_KEYS);
120
+ if (keys.length > MAX_REDACTED_KEYS) {
121
+ record.KeysElided = true;
122
+ }
123
+ }
124
+ }
125
+ /**
126
+ * UTF-8 byte length of a value's JSON form. Returns `-1` when the value cannot be
127
+ * serialized (a circular reference, say) — a distinguishable signal rather than a
128
+ * misleading zero, and never a reason to throw out of a logging path.
129
+ */
130
+ function utf8ByteLength(value) {
131
+ try {
132
+ const json = JSON.stringify(value);
133
+ if (json === undefined) {
134
+ return 0;
135
+ }
136
+ return new TextEncoder().encode(json).length;
137
+ }
138
+ catch {
139
+ return -1;
140
+ }
141
+ }
142
+ //# sourceMappingURL=ParamRedaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParamRedaction.js","sourceRoot":"","sources":["../src/ParamRedaction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=EntityActionEngine-Base.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityActionEngine-Base.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/EntityActionEngine-Base.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,160 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ const mockEntityByID = vi.fn();
3
+ vi.mock('@memberjunction/core', () => ({
4
+ BaseEngine: class BaseEngine {
5
+ static getInstance(_key) {
6
+ return {};
7
+ }
8
+ async Load() { }
9
+ },
10
+ BaseEnginePropertyConfig: class BaseEnginePropertyConfig {
11
+ },
12
+ BaseEntity: class BaseEntity {
13
+ },
14
+ EntityInfo: class EntityInfo {
15
+ },
16
+ IMetadataProvider: class IMetadataProvider {
17
+ },
18
+ UserInfo: class UserInfo {
19
+ },
20
+ Metadata: class Metadata {
21
+ EntityByID(id) {
22
+ return mockEntityByID(id);
23
+ }
24
+ },
25
+ RunView: class RunView {
26
+ }
27
+ }));
28
+ vi.mock('@memberjunction/core-entities', () => ({}));
29
+ import { EntityActionEngineBase } from '../EntityActionEngine-Base.js';
30
+ const DEAL_TYPES_ID = 'AAAAAAAA-0000-0000-0000-000000000001';
31
+ const SCOPE_RECORD_ID = 'CCCCCCCC-0000-0000-0000-000000000003';
32
+ const DEALS_ENTITY_ID = 'EEEEEEEE-0000-0000-0000-000000000005';
33
+ function bindingRow(spec) {
34
+ return {
35
+ Entity: spec.Entity ?? 'Deals',
36
+ EntityID: spec.EntityID ?? DEALS_ENTITY_ID,
37
+ Status: spec.Status ?? 'Active',
38
+ ScopeEntityID: spec.ScopeEntityID ?? null,
39
+ ScopeRecordID: spec.ScopeRecordID ?? null,
40
+ ...spec
41
+ };
42
+ }
43
+ /**
44
+ * A live engine instance with its cache pre-seeded. The engine's cached arrays are private and
45
+ * normally filled by `Config()`; seeding them directly is what lets these tests exercise the pure
46
+ * ordering/filtering logic without a database.
47
+ */
48
+ function engineWith(bindings) {
49
+ const engine = new EntityActionEngineBase();
50
+ engine._EntityActions = bindings;
51
+ return engine;
52
+ }
53
+ function dealRecord(dealTypeID) {
54
+ return {
55
+ EntityInfo: { Fields: [{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }] },
56
+ Get: (name) => (name === 'DealTypeID' ? dealTypeID : undefined)
57
+ };
58
+ }
59
+ describe('EntityActionEngineBase — Sequence ordering', () => {
60
+ it('returns bindings in ascending Sequence order', () => {
61
+ const engine = engineWith([
62
+ bindingRow({ Action: 'Notify', Sequence: 30 }),
63
+ bindingRow({ Action: 'Normalize', Sequence: 10 }),
64
+ bindingRow({ Action: 'Validate', Sequence: 20 })
65
+ ]);
66
+ expect(engine.GetActionsByEntityName('Deals').map(e => e.Action)).toEqual(['Normalize', 'Validate', 'Notify']);
67
+ });
68
+ it('breaks Sequence ties by Action name so the order is total and stable', () => {
69
+ const engine = engineWith([
70
+ bindingRow({ Action: 'Zulu', Sequence: 5 }),
71
+ bindingRow({ Action: 'Alpha', Sequence: 5 }),
72
+ bindingRow({ Action: 'Mike', Sequence: 5 })
73
+ ]);
74
+ expect(engine.GetActionsByEntityName('Deals').map(e => e.Action)).toEqual(['Alpha', 'Mike', 'Zulu']);
75
+ });
76
+ it('treats a null Sequence as 0, so unsequenced bindings run before deliberately-later ones', () => {
77
+ const engine = engineWith([
78
+ bindingRow({ Action: 'Later', Sequence: 100 }),
79
+ bindingRow({ Action: 'Unsequenced', Sequence: null }),
80
+ bindingRow({ Action: 'Explicit Zero', Sequence: 0 })
81
+ ]);
82
+ expect(engine.GetActionsByEntityName('Deals').map(e => e.Action)).toEqual([
83
+ 'Explicit Zero',
84
+ 'Unsequenced',
85
+ 'Later'
86
+ ]);
87
+ });
88
+ it('supports negative Sequence for a binding that must run first', () => {
89
+ const engine = engineWith([
90
+ bindingRow({ Action: 'Default', Sequence: 0 }),
91
+ bindingRow({ Action: 'Preflight', Sequence: -10 })
92
+ ]);
93
+ expect(engine.GetActionsByEntityName('Deals').map(e => e.Action)).toEqual(['Preflight', 'Default']);
94
+ });
95
+ it('does not mutate the cached array — ordering must not reorder the engine cache', () => {
96
+ const cached = [bindingRow({ Action: 'B', Sequence: 2 }), bindingRow({ Action: 'A', Sequence: 1 })];
97
+ const engine = engineWith(cached);
98
+ engine.GetActionsByEntityName('Deals');
99
+ expect(cached.map(e => e.Action)).toEqual(['B', 'A']);
100
+ });
101
+ it('orders GetActionsByEntityID the same way', () => {
102
+ const engine = engineWith([
103
+ bindingRow({ Action: 'Second', Sequence: 2 }),
104
+ bindingRow({ Action: 'First', Sequence: 1 })
105
+ ]);
106
+ expect(engine.GetActionsByEntityID(DEALS_ENTITY_ID).map(e => e.Action)).toEqual(['First', 'Second']);
107
+ });
108
+ it('still honours the entity-name and status filters', () => {
109
+ const engine = engineWith([
110
+ bindingRow({ Action: 'OtherEntity', Sequence: 1, Entity: 'Contacts' }),
111
+ bindingRow({ Action: 'Disabled', Sequence: 2, Status: 'Disabled' }),
112
+ bindingRow({ Action: 'Active', Sequence: 3 })
113
+ ]);
114
+ expect(engine.GetActionsByEntityName('Deals', 'Active').map(e => e.Action)).toEqual(['Active']);
115
+ // Entity name matching is case/whitespace-insensitive, as before.
116
+ expect(engine.GetActionsByEntityName(' deals ').map(e => e.Action)).toEqual([
117
+ 'Disabled',
118
+ 'Active'
119
+ ]);
120
+ });
121
+ });
122
+ describe('EntityActionEngineBase — FilterByScope', () => {
123
+ beforeEach(() => {
124
+ mockEntityByID.mockReset();
125
+ mockEntityByID.mockImplementation((id) => (id === DEAL_TYPES_ID ? { Name: 'Deal Types' } : undefined));
126
+ });
127
+ it('keeps unscoped bindings and drops scoped ones the record falls outside of', async () => {
128
+ const engine = engineWith([]);
129
+ const bindings = [
130
+ bindingRow({ Action: 'Applies To All', Sequence: 1 }),
131
+ bindingRow({ Action: 'Scoped Match', Sequence: 2, ScopeEntityID: DEAL_TYPES_ID, ScopeRecordID: SCOPE_RECORD_ID }),
132
+ bindingRow({ Action: 'Scoped Other', Sequence: 3, ScopeEntityID: DEAL_TYPES_ID, ScopeRecordID: 'a-different-type' })
133
+ ];
134
+ const kept = await engine.FilterByScope(bindings, dealRecord(SCOPE_RECORD_ID));
135
+ expect(kept.map(e => e.Action)).toEqual(['Applies To All', 'Scoped Match']);
136
+ });
137
+ it('preserves the incoming Sequence ordering', async () => {
138
+ const engine = engineWith([]);
139
+ const bindings = engine.GetActionsByEntityName.call(engineWith([
140
+ bindingRow({ Action: 'Third', Sequence: 3 }),
141
+ bindingRow({ Action: 'First', Sequence: 1 }),
142
+ bindingRow({ Action: 'Second', Sequence: 2 })
143
+ ]), 'Deals');
144
+ const kept = await engine.FilterByScope(bindings, dealRecord(SCOPE_RECORD_ID));
145
+ expect(kept.map(e => e.Action)).toEqual(['First', 'Second', 'Third']);
146
+ });
147
+ it('drops every scoped binding when there is no subject record to evaluate', async () => {
148
+ const engine = engineWith([]);
149
+ const bindings = [
150
+ bindingRow({ Action: 'Unscoped' }),
151
+ bindingRow({ Action: 'Scoped', ScopeEntityID: DEAL_TYPES_ID, ScopeRecordID: SCOPE_RECORD_ID })
152
+ ];
153
+ const kept = await engine.FilterByScope(bindings, undefined);
154
+ expect(kept.map(e => e.Action)).toEqual(['Unscoped']);
155
+ });
156
+ it('returns an empty array for an empty candidate set', async () => {
157
+ await expect(engineWith([]).FilterByScope([], dealRecord(SCOPE_RECORD_ID))).resolves.toEqual([]);
158
+ });
159
+ });
160
+ //# sourceMappingURL=EntityActionEngine-Base.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityActionEngine-Base.test.js","sourceRoot":"","sources":["../../src/__tests__/EntityActionEngine-Base.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=EntityActionScopeResolver.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityActionScopeResolver.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/EntityActionScopeResolver.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,149 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ /**
3
+ * The scope resolver reads two things: an entity's field metadata (to walk foreign keys) and the
4
+ * `Metadata` catalog (to turn `ScopeEntityID` into an entity name for resolver lookup). Both are
5
+ * mocked so the tests are pure and deterministic.
6
+ */
7
+ const mockEntityByID = vi.fn();
8
+ vi.mock('@memberjunction/core', () => ({
9
+ BaseEntity: class BaseEntity {
10
+ },
11
+ EntityInfo: class EntityInfo {
12
+ },
13
+ Metadata: class Metadata {
14
+ EntityByID(id) {
15
+ return mockEntityByID(id);
16
+ }
17
+ }
18
+ }));
19
+ import { EntityActionScopeResolver, IsEntityActionInScope } from '../EntityActionScopeResolver.js';
20
+ // ── Fixtures ─────────────────────────────────────────────────────────────────────────────────────
21
+ const DEAL_TYPES_ID = 'AAAAAAAA-0000-0000-0000-000000000001';
22
+ const COMPANIES_ID = 'BBBBBBBB-0000-0000-0000-000000000002';
23
+ const SCOPE_RECORD_ID = 'CCCCCCCC-0000-0000-0000-000000000003';
24
+ /** A subject record with the given FK fields and values. */
25
+ function subject(fields, values) {
26
+ return {
27
+ EntityInfo: { Fields: fields },
28
+ Get: (name) => values[name]
29
+ };
30
+ }
31
+ function entityAction(scopeEntityID, scopeRecordID) {
32
+ return { ScopeEntityID: scopeEntityID, ScopeRecordID: scopeRecordID };
33
+ }
34
+ /** The default resolver, used wherever a test isn't exercising a custom registration. */
35
+ const defaultResolverFactory = () => new EntityActionScopeResolver();
36
+ describe('EntityActionScopeResolver — default foreign-key walk', () => {
37
+ const resolver = new EntityActionScopeResolver();
38
+ it('matches when the single FK to the scope entity holds the scope record ID', async () => {
39
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: SCOPE_RECORD_ID });
40
+ await expect(resolver.IsInScope(deal, DEAL_TYPES_ID, SCOPE_RECORD_ID)).resolves.toBe(true);
41
+ });
42
+ it('rejects when the FK points at a different scope record', async () => {
43
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], {
44
+ DealTypeID: 'DDDDDDDD-0000-0000-0000-00000000000D'
45
+ });
46
+ await expect(resolver.IsInScope(deal, DEAL_TYPES_ID, SCOPE_RECORD_ID)).resolves.toBe(false);
47
+ });
48
+ it('compares UUIDs case-insensitively — SQL Server uppercases, PostgreSQL lowercases', async () => {
49
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], {
50
+ DealTypeID: SCOPE_RECORD_ID.toLowerCase()
51
+ });
52
+ await expect(resolver.IsInScope(deal, DEAL_TYPES_ID, SCOPE_RECORD_ID.toUpperCase())).resolves.toBe(true);
53
+ });
54
+ it('matches non-UUID (numeric/text) scope record keys', async () => {
55
+ const deal = subject([{ Name: 'RegionID', RelatedEntityID: DEAL_TYPES_ID }], { RegionID: 42 });
56
+ await expect(resolver.IsInScope(deal, DEAL_TYPES_ID, '42')).resolves.toBe(true);
57
+ await expect(resolver.IsInScope(deal, DEAL_TYPES_ID, '43')).resolves.toBe(false);
58
+ });
59
+ it('rejects when the FK is null on this record', async () => {
60
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: null });
61
+ await expect(resolver.IsInScope(deal, DEAL_TYPES_ID, SCOPE_RECORD_ID)).resolves.toBe(false);
62
+ });
63
+ it('DECLINES (null) when the subject has no FK to the scope entity — the relationship is indirect', async () => {
64
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: SCOPE_RECORD_ID });
65
+ await expect(resolver.IsInScope(deal, COMPANIES_ID, SCOPE_RECORD_ID)).resolves.toBeNull();
66
+ });
67
+ it('DECLINES (null) on ambiguity — two FKs to the same entity have no defensible "the" one', async () => {
68
+ const deal = subject([
69
+ { Name: 'OwnerCompanyID', RelatedEntityID: COMPANIES_ID },
70
+ { Name: 'ClientCompanyID', RelatedEntityID: COMPANIES_ID }
71
+ ], { OwnerCompanyID: SCOPE_RECORD_ID, ClientCompanyID: 'other' });
72
+ await expect(resolver.IsInScope(deal, COMPANIES_ID, SCOPE_RECORD_ID)).resolves.toBeNull();
73
+ });
74
+ it('ignores non-FK fields when looking for the scope relationship', async () => {
75
+ const deal = subject([{ Name: 'Amount' }, { Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { Amount: 100, DealTypeID: SCOPE_RECORD_ID });
76
+ await expect(resolver.IsInScope(deal, DEAL_TYPES_ID, SCOPE_RECORD_ID)).resolves.toBe(true);
77
+ });
78
+ });
79
+ describe('IsEntityActionInScope', () => {
80
+ beforeEach(() => {
81
+ mockEntityByID.mockReset();
82
+ mockEntityByID.mockImplementation((id) => (id === DEAL_TYPES_ID ? { Name: 'Deal Types' } : undefined));
83
+ });
84
+ it('an unscoped binding always applies — the pre-existing behaviour', async () => {
85
+ const deal = subject([], {});
86
+ await expect(IsEntityActionInScope(entityAction(null, null), deal, defaultResolverFactory)).resolves.toBe(true);
87
+ });
88
+ it('a half-configured scope (entity but no record) is treated as unscoped', async () => {
89
+ const deal = subject([], {});
90
+ await expect(IsEntityActionInScope(entityAction(DEAL_TYPES_ID, null), deal, defaultResolverFactory)).resolves.toBe(true);
91
+ await expect(IsEntityActionInScope(entityAction(null, SCOPE_RECORD_ID), deal, defaultResolverFactory)).resolves.toBe(true);
92
+ });
93
+ it('an unscoped binding applies even with no subject record in hand', async () => {
94
+ await expect(IsEntityActionInScope(entityAction(null, null), undefined, defaultResolverFactory)).resolves.toBe(true);
95
+ });
96
+ it('a scoped binding applies when the default FK walk matches', async () => {
97
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: SCOPE_RECORD_ID });
98
+ await expect(IsEntityActionInScope(entityAction(DEAL_TYPES_ID, SCOPE_RECORD_ID), deal, defaultResolverFactory)).resolves.toBe(true);
99
+ });
100
+ it('a scoped binding does NOT apply to a record under a different scope record', async () => {
101
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: 'someone-else' });
102
+ await expect(IsEntityActionInScope(entityAction(DEAL_TYPES_ID, SCOPE_RECORD_ID), deal, defaultResolverFactory)).resolves.toBe(false);
103
+ });
104
+ it('a scoped binding does NOT fire when there is no subject record to evaluate', async () => {
105
+ await expect(IsEntityActionInScope(entityAction(DEAL_TYPES_ID, SCOPE_RECORD_ID), null, defaultResolverFactory)).resolves.toBe(false);
106
+ });
107
+ it('a scoped binding does NOT fire when the scope entity is unknown to metadata', async () => {
108
+ const deal = subject([{ Name: 'CompanyID', RelatedEntityID: COMPANIES_ID }], { CompanyID: SCOPE_RECORD_ID });
109
+ await expect(IsEntityActionInScope(entityAction(COMPANIES_ID, SCOPE_RECORD_ID), deal, defaultResolverFactory)).resolves.toBe(false);
110
+ });
111
+ it('a scoped binding does NOT fire when no resolver can be produced', async () => {
112
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: SCOPE_RECORD_ID });
113
+ await expect(IsEntityActionInScope(entityAction(DEAL_TYPES_ID, SCOPE_RECORD_ID), deal, () => null)).resolves.toBe(false);
114
+ });
115
+ it('a resolver that DECLINES (null) leaves the binding not-applicable — declining is not approval', async () => {
116
+ class DecliningResolver extends EntityActionScopeResolver {
117
+ async IsInScope() {
118
+ return null;
119
+ }
120
+ }
121
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: SCOPE_RECORD_ID });
122
+ await expect(IsEntityActionInScope(entityAction(DEAL_TYPES_ID, SCOPE_RECORD_ID), deal, () => new DecliningResolver())).resolves.toBe(false);
123
+ });
124
+ it('an app-specific resolver overrides the default FK walk in both directions', async () => {
125
+ class AlwaysInScope extends EntityActionScopeResolver {
126
+ async IsInScope() {
127
+ return true;
128
+ }
129
+ }
130
+ class NeverInScope extends EntityActionScopeResolver {
131
+ async IsInScope() {
132
+ return false;
133
+ }
134
+ }
135
+ // No FK at all — the default walk would decline, but the app resolver says yes.
136
+ const orphan = subject([], {});
137
+ await expect(IsEntityActionInScope(entityAction(DEAL_TYPES_ID, SCOPE_RECORD_ID), orphan, () => new AlwaysInScope())).resolves.toBe(true);
138
+ // FK matches — the default walk would say yes, but the app resolver says no.
139
+ const matching = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: SCOPE_RECORD_ID });
140
+ await expect(IsEntityActionInScope(entityAction(DEAL_TYPES_ID, SCOPE_RECORD_ID), matching, () => new NeverInScope())).resolves.toBe(false);
141
+ });
142
+ it('looks the resolver up by the scope entity NAME', async () => {
143
+ const lookup = vi.fn().mockReturnValue(new EntityActionScopeResolver());
144
+ const deal = subject([{ Name: 'DealTypeID', RelatedEntityID: DEAL_TYPES_ID }], { DealTypeID: SCOPE_RECORD_ID });
145
+ await IsEntityActionInScope(entityAction(DEAL_TYPES_ID, SCOPE_RECORD_ID), deal, lookup);
146
+ expect(lookup).toHaveBeenCalledWith('Deal Types');
147
+ });
148
+ });
149
+ //# sourceMappingURL=EntityActionScopeResolver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EntityActionScopeResolver.test.js","sourceRoot":"","sources":["../../src/__tests__/EntityActionScopeResolver.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ParamRedaction.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ParamRedaction.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/ParamRedaction.test.ts"],"names":[],"mappings":""}