@twin.org/rights-management-plugins 0.0.3-next.29 → 0.0.3-next.31
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/dist/es/index.js +5 -2
- package/dist/es/index.js.map +1 -1
- package/dist/es/models/IAutomationPolicyExecutionActionConfig.js +4 -0
- package/dist/es/models/IAutomationPolicyExecutionActionConfig.js.map +1 -0
- package/dist/es/models/IAutomationPolicyExecutionActionConstructorOptions.js +2 -0
- package/dist/es/models/IAutomationPolicyExecutionActionConstructorOptions.js.map +1 -0
- package/dist/es/policyArbiters/defaultPolicyArbiter.js +270 -90
- package/dist/es/policyArbiters/defaultPolicyArbiter.js.map +1 -1
- package/dist/es/policyExecutionActions/automationPolicyExecutionAction.js +76 -0
- package/dist/es/policyExecutionActions/automationPolicyExecutionAction.js.map +1 -0
- package/dist/es/policyExecutionActions/loggingPolicyExecutionAction.js.map +1 -1
- package/dist/types/index.d.ts +5 -2
- package/dist/types/models/IAutomationPolicyExecutionActionConfig.d.ts +9 -0
- package/dist/types/models/IAutomationPolicyExecutionActionConstructorOptions.d.ts +15 -0
- package/dist/types/policyExecutionActions/automationPolicyExecutionAction.d.ts +49 -0
- package/dist/types/policyExecutionActions/loggingPolicyExecutionAction.d.ts +1 -1
- package/docs/changelog.md +100 -48
- package/docs/examples.md +0 -29
- package/docs/reference/classes/AutomationPolicyExecutionAction.md +143 -0
- package/docs/reference/classes/LoggingPolicyExecutionAction.md +1 -1
- package/docs/reference/index.md +3 -0
- package/docs/reference/interfaces/IAutomationPolicyExecutionActionConfig.md +11 -0
- package/docs/reference/interfaces/IAutomationPolicyExecutionActionConstructorOptions.md +25 -0
- package/locales/en.json +2 -1
- package/package.json +3 -2
package/dist/es/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// Copyright 2025 IOTA Stiftung.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0.
|
|
3
|
-
export * from "./models/
|
|
3
|
+
export * from "./models/IAutomationPolicyExecutionActionConfig.js";
|
|
4
|
+
export * from "./models/IAutomationPolicyExecutionActionConstructorOptions.js";
|
|
4
5
|
export * from "./models/IDefaultPolicyArbiterConfig.js";
|
|
6
|
+
export * from "./models/IDefaultPolicyArbiterConstructorOptions.js";
|
|
5
7
|
export * from "./models/IDefaultPolicyEnforcementProcessorConstructorOptions.js";
|
|
6
8
|
export * from "./models/IIdentityPolicyInformationSourceConstructorOptions.js";
|
|
7
9
|
export * from "./models/ILoggingPolicyExecutionActionConfig.js";
|
|
@@ -18,10 +20,11 @@ export * from "./policyArbiters/defaultPolicyArbiter.js";
|
|
|
18
20
|
export * from "./policyArbiters/passThroughPolicyArbiter.js";
|
|
19
21
|
export * from "./policyEnforcementProcessor/defaultPolicyEnforcementProcessor.js";
|
|
20
22
|
export * from "./policyEnforcementProcessor/passThroughPolicyEnforcementProcessor.js";
|
|
23
|
+
export * from "./policyExecutionActions/automationPolicyExecutionAction.js";
|
|
21
24
|
export * from "./policyExecutionActions/loggingPolicyExecutionAction.js";
|
|
22
|
-
export * from "./policyObligationEnforcers/passThroughPolicyObligationEnforcer.js";
|
|
23
25
|
export * from "./policyInformationSources/identityPolicyInformationSource.js";
|
|
24
26
|
export * from "./policyInformationSources/staticPolicyInformationSource.js";
|
|
25
27
|
export * from "./policyNegotiators/passThroughPolicyNegotiator.js";
|
|
28
|
+
export * from "./policyObligationEnforcers/passThroughPolicyObligationEnforcer.js";
|
|
26
29
|
export * from "./policyRequesters/passThroughPolicyRequester.js";
|
|
27
30
|
//# sourceMappingURL=index.js.map
|
package/dist/es/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,oDAAoD,CAAC;AACnE,cAAc,gEAAgE,CAAC;AAC/E,cAAc,yCAAyC,CAAC;AACxD,cAAc,qDAAqD,CAAC;AACpE,cAAc,kEAAkE,CAAC;AACjF,cAAc,gEAAgE,CAAC;AAC/E,cAAc,iDAAiD,CAAC;AAChE,cAAc,6DAA6D,CAAC;AAC5E,cAAc,yDAAyD,CAAC;AACxE,cAAc,sEAAsE,CAAC;AACrF,cAAc,4DAA4D,CAAC;AAC3E,cAAc,oEAAoE,CAAC;AACnF,cAAc,2DAA2D,CAAC;AAC1E,cAAc,4CAA4C,CAAC;AAC3D,cAAc,kDAAkD,CAAC;AACjE,cAAc,8DAA8D,CAAC;AAC7E,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,mEAAmE,CAAC;AAClF,cAAc,uEAAuE,CAAC;AACtF,cAAc,6DAA6D,CAAC;AAC5E,cAAc,0DAA0D,CAAC;AACzE,cAAc,+DAA+D,CAAC;AAC9E,cAAc,6DAA6D,CAAC;AAC5E,cAAc,oDAAoD,CAAC;AACnE,cAAc,oEAAoE,CAAC;AACnF,cAAc,kDAAkD,CAAC","sourcesContent":["// Copyright 2025 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./models/IAutomationPolicyExecutionActionConfig.js\";\nexport * from \"./models/IAutomationPolicyExecutionActionConstructorOptions.js\";\nexport * from \"./models/IDefaultPolicyArbiterConfig.js\";\nexport * from \"./models/IDefaultPolicyArbiterConstructorOptions.js\";\nexport * from \"./models/IDefaultPolicyEnforcementProcessorConstructorOptions.js\";\nexport * from \"./models/IIdentityPolicyInformationSourceConstructorOptions.js\";\nexport * from \"./models/ILoggingPolicyExecutionActionConfig.js\";\nexport * from \"./models/ILoggingPolicyExecutionActionConstructorOptions.js\";\nexport * from \"./models/IPassThroughPolicyArbiterConstructorOptions.js\";\nexport * from \"./models/IPassThroughPolicyEnforcementProcessorConstructorOptions.js\";\nexport * from \"./models/IPassThroughPolicyNegotiatorConstructorOptions.js\";\nexport * from \"./models/IPassThroughPolicyObligationEnforcerConstructorOptions.js\";\nexport * from \"./models/IPassThroughPolicyRequesterConstructorOptions.js\";\nexport * from \"./models/IStaticPolicyInformationSource.js\";\nexport * from \"./models/IStaticPolicyInformationSourceConfig.js\";\nexport * from \"./models/IStaticPolicyInformationSourceConstructorOptions.js\";\nexport * from \"./policyArbiters/defaultPolicyArbiter.js\";\nexport * from \"./policyArbiters/passThroughPolicyArbiter.js\";\nexport * from \"./policyEnforcementProcessor/defaultPolicyEnforcementProcessor.js\";\nexport * from \"./policyEnforcementProcessor/passThroughPolicyEnforcementProcessor.js\";\nexport * from \"./policyExecutionActions/automationPolicyExecutionAction.js\";\nexport * from \"./policyExecutionActions/loggingPolicyExecutionAction.js\";\nexport * from \"./policyInformationSources/identityPolicyInformationSource.js\";\nexport * from \"./policyInformationSources/staticPolicyInformationSource.js\";\nexport * from \"./policyNegotiators/passThroughPolicyNegotiator.js\";\nexport * from \"./policyObligationEnforcers/passThroughPolicyObligationEnforcer.js\";\nexport * from \"./policyRequesters/passThroughPolicyRequester.js\";\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IAutomationPolicyExecutionActionConfig.js","sourceRoot":"","sources":["../../../src/models/IAutomationPolicyExecutionActionConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Options for the Automation Policy Execution Action Component.\n */\nexport interface IAutomationPolicyExecutionActionConfig {\n\t/**\n\t * The policy decision stages to trigger the automation actions, if undefined defaults to \"inform\".\n\t */\n\ttriggerActions?: string[];\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IAutomationPolicyExecutionActionConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/IAutomationPolicyExecutionActionConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2026 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { IAutomationPolicyExecutionActionConfig } from \"./IAutomationPolicyExecutionActionConfig.js\";\n\n/**\n * Options for the Automation Policy Execution Action.\n */\nexport interface IAutomationPolicyExecutionActionConstructorOptions {\n\t/**\n\t * The automation component for executing automation policies.\n\t * @default automation\n\t */\n\tautomationComponentType?: string;\n\n\t/**\n\t * The configuration for the automation policy execution.\n\t */\n\tconfig?: IAutomationPolicyExecutionActionConfig;\n}\n"]}
|
|
@@ -24,20 +24,31 @@ export class DefaultPolicyArbiter {
|
|
|
24
24
|
*/
|
|
25
25
|
static _DEFAULT_MAX_INHERITANCE_DEPTH = 10;
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* Datasource key for the primary JSON path data source.
|
|
28
28
|
* @internal
|
|
29
29
|
*/
|
|
30
|
-
static
|
|
30
|
+
static _DATA_SOURCE_KEY = "data";
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* Datasource key for the information source used in JSON path expressions.
|
|
33
33
|
* @internal
|
|
34
34
|
*/
|
|
35
|
-
static
|
|
35
|
+
static _INFORMATION_SOURCE_KEY = "information";
|
|
36
36
|
/**
|
|
37
|
-
* TWIN prefix
|
|
37
|
+
* TWIN prefix JSONPath canonical alias.
|
|
38
38
|
* @internal
|
|
39
39
|
*/
|
|
40
|
-
static
|
|
40
|
+
static _TWIN_JSONPATH = "twin:jsonPath";
|
|
41
|
+
/**
|
|
42
|
+
* Canonical jsonPath expression property.
|
|
43
|
+
* @internal
|
|
44
|
+
*/
|
|
45
|
+
static _TWIN_JSONPATH_EXPRESSION = "twin:jsonPathExpression";
|
|
46
|
+
/**
|
|
47
|
+
* Optional data source key property for canonical twin:jsonPath targets.
|
|
48
|
+
* When absent, defaults to the primary data source.
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
static _TWIN_JSONPATH_DATA_SOURCE = "twin:jsonPathDataSource";
|
|
41
52
|
/**
|
|
42
53
|
* The logging component.
|
|
43
54
|
* @internal
|
|
@@ -141,8 +152,8 @@ export class DefaultPolicyArbiter {
|
|
|
141
152
|
const mergedPolicy = await this.mergeInheritedPolicies(agreement);
|
|
142
153
|
const expandedPolicy = this.expandCompactPolicyRules(mergedPolicy);
|
|
143
154
|
const dataSources = {
|
|
144
|
-
[
|
|
145
|
-
[
|
|
155
|
+
[DefaultPolicyArbiter._DATA_SOURCE_KEY]: data,
|
|
156
|
+
[DefaultPolicyArbiter._INFORMATION_SOURCE_KEY]: information
|
|
146
157
|
};
|
|
147
158
|
// Extract agreement parties once for use in rule evaluation
|
|
148
159
|
const agreementAssigner = OdrlPolicyHelper.getPartyIds(agreement.assigner);
|
|
@@ -797,7 +808,7 @@ export class DefaultPolicyArbiter {
|
|
|
797
808
|
*/
|
|
798
809
|
async enforceDuty(policy, duty, dataSources, ruleDataContext) {
|
|
799
810
|
const enforcerNames = PolicyObligationEnforcerFactory.names();
|
|
800
|
-
const information = dataSources[
|
|
811
|
+
const information = dataSources[DefaultPolicyArbiter._INFORMATION_SOURCE_KEY];
|
|
801
812
|
if (enforcerNames.length === 0) {
|
|
802
813
|
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "noObligationEnforcersRegistered");
|
|
803
814
|
}
|
|
@@ -827,51 +838,70 @@ export class DefaultPolicyArbiter {
|
|
|
827
838
|
* @internal
|
|
828
839
|
*/
|
|
829
840
|
tryResolveTargetDataSource(targetId, dataSources, resolveValue = false) {
|
|
830
|
-
// If there is no target id, default to the
|
|
841
|
+
// If there is no target id, default to the data datasource
|
|
831
842
|
if (Is.empty(targetId)) {
|
|
832
843
|
return {
|
|
833
|
-
|
|
834
|
-
source: dataSources[`${DefaultPolicyArbiter._TWIN_PREFIX_OPERATIONS}${DefaultPolicyArbiter._TWIN_PREFIX_JSONPATH}`],
|
|
844
|
+
source: dataSources[DefaultPolicyArbiter._DATA_SOURCE_KEY],
|
|
835
845
|
target: "$",
|
|
836
|
-
value: dataSources[
|
|
846
|
+
value: dataSources[DefaultPolicyArbiter._DATA_SOURCE_KEY]
|
|
837
847
|
};
|
|
838
848
|
}
|
|
839
|
-
//
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
target
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
|
-
const matches = JsonPathHelper.query(target, source);
|
|
858
|
-
if (matches.length === 0) {
|
|
859
|
-
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "ruleTargetNotSupported", {
|
|
860
|
-
target: targetId
|
|
861
|
-
});
|
|
862
|
-
}
|
|
863
|
-
return {
|
|
864
|
-
prefix,
|
|
865
|
-
source,
|
|
866
|
-
target,
|
|
867
|
-
value: matches.length === 1 ? matches[0].value : matches.map(m => m.value)
|
|
868
|
-
};
|
|
869
|
-
}
|
|
849
|
+
// Handle twin:jsonPath:<datasource>:<expression> format.
|
|
850
|
+
// The datasource segment is optional; when absent the expression starts with "$"
|
|
851
|
+
// and falls back to the primary data source.
|
|
852
|
+
if (targetId.startsWith(`${DefaultPolicyArbiter._TWIN_JSONPATH}:`)) {
|
|
853
|
+
const rest = targetId.slice(DefaultPolicyArbiter._TWIN_JSONPATH.length + 1);
|
|
854
|
+
const matchingKey = Object.keys(dataSources).find(k => rest.startsWith(`${k}:`));
|
|
855
|
+
const sourceKey = matchingKey ?? DefaultPolicyArbiter._DATA_SOURCE_KEY;
|
|
856
|
+
const expression = matchingKey ? rest.slice(matchingKey.length + 1) : rest;
|
|
857
|
+
return this.resolveDataSourceByKey(sourceKey, expression, dataSources, resolveValue);
|
|
858
|
+
}
|
|
859
|
+
// Handle <datasource>:<expression> format
|
|
860
|
+
const matchingKey = Object.keys(dataSources).find(k => targetId.startsWith(`${k}:`));
|
|
861
|
+
if (matchingKey) {
|
|
862
|
+
const expression = targetId.slice(matchingKey.length + 1);
|
|
863
|
+
return this.resolveDataSourceByKey(matchingKey, expression, dataSources, resolveValue);
|
|
870
864
|
}
|
|
871
865
|
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "ruleTargetNotSupported", {
|
|
872
866
|
target: targetId
|
|
873
867
|
});
|
|
874
868
|
}
|
|
869
|
+
/**
|
|
870
|
+
* Resolve a datasource by key and evaluate a JSONPath expression against it.
|
|
871
|
+
* @param sourceKey The datasource key.
|
|
872
|
+
* @param expression The JSONPath expression.
|
|
873
|
+
* @param dataSources The available datasources.
|
|
874
|
+
* @param resolveValue Whether to evaluate the expression and return the matched value.
|
|
875
|
+
* @returns The resolved source, target expression, and optionally the matched value.
|
|
876
|
+
* @internal
|
|
877
|
+
*/
|
|
878
|
+
resolveDataSourceByKey(sourceKey, expression, dataSources, resolveValue = false) {
|
|
879
|
+
if (!Is.stringValue(expression)) {
|
|
880
|
+
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "jsonPathExpressionMissing", {
|
|
881
|
+
operand: "target"
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
if (!expression.startsWith("$")) {
|
|
885
|
+
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "ruleTargetNotSupported", {
|
|
886
|
+
target: `${sourceKey}:${expression}`
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
const source = dataSources[sourceKey];
|
|
890
|
+
if (!resolveValue) {
|
|
891
|
+
return { source, target: expression };
|
|
892
|
+
}
|
|
893
|
+
const matches = JsonPathHelper.query(expression, source);
|
|
894
|
+
if (matches.length === 0) {
|
|
895
|
+
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "ruleTargetNotSupported", {
|
|
896
|
+
target: `${sourceKey}:${expression}`
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
return {
|
|
900
|
+
source,
|
|
901
|
+
target: expression,
|
|
902
|
+
value: matches.length === 1 ? matches[0].value : matches.map(m => m.value)
|
|
903
|
+
};
|
|
904
|
+
}
|
|
875
905
|
/**
|
|
876
906
|
* Extract the target id from the permission.
|
|
877
907
|
* @param target The permission target.
|
|
@@ -889,7 +919,23 @@ export class DefaultPolicyArbiter {
|
|
|
889
919
|
if (arr.length === 0) {
|
|
890
920
|
return undefined;
|
|
891
921
|
}
|
|
892
|
-
|
|
922
|
+
const first = arr[0];
|
|
923
|
+
if (Is.string(first)) {
|
|
924
|
+
return first;
|
|
925
|
+
}
|
|
926
|
+
if (this.isTwinJsonPathTarget(first)) {
|
|
927
|
+
const t = first;
|
|
928
|
+
const expression = t[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION];
|
|
929
|
+
if (!Is.stringValue(expression)) {
|
|
930
|
+
return undefined;
|
|
931
|
+
}
|
|
932
|
+
const dataSource = t[DefaultPolicyArbiter._TWIN_JSONPATH_DATA_SOURCE];
|
|
933
|
+
const sourceKey = Is.stringValue(dataSource)
|
|
934
|
+
? dataSource
|
|
935
|
+
: DefaultPolicyArbiter._DATA_SOURCE_KEY;
|
|
936
|
+
return `${sourceKey}:${expression}`;
|
|
937
|
+
}
|
|
938
|
+
return OdrlPolicyHelper.getUid(first);
|
|
893
939
|
}
|
|
894
940
|
/**
|
|
895
941
|
* Resolve the target identifier used for rule data context lookup.
|
|
@@ -905,8 +951,16 @@ export class DefaultPolicyArbiter {
|
|
|
905
951
|
const firstTarget = arr[0];
|
|
906
952
|
if (Is.object(firstTarget) &&
|
|
907
953
|
OdrlPolicyHelper.getType(firstTarget) === OdrlTypes.AssetCollection &&
|
|
908
|
-
|
|
909
|
-
|
|
954
|
+
firstTarget.source === DefaultPolicyArbiter._TWIN_JSONPATH) {
|
|
955
|
+
const ctx = firstTarget;
|
|
956
|
+
const expression = ctx[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION];
|
|
957
|
+
if (Is.stringValue(expression)) {
|
|
958
|
+
const dataSource = ctx[DefaultPolicyArbiter._TWIN_JSONPATH_DATA_SOURCE];
|
|
959
|
+
const sourceKey = Is.stringValue(dataSource)
|
|
960
|
+
? dataSource
|
|
961
|
+
: DefaultPolicyArbiter._DATA_SOURCE_KEY;
|
|
962
|
+
return `${DefaultPolicyArbiter._TWIN_JSONPATH}:${sourceKey}:${expression}`;
|
|
963
|
+
}
|
|
910
964
|
}
|
|
911
965
|
}
|
|
912
966
|
return this.getTargetId(target);
|
|
@@ -952,6 +1006,14 @@ export class DefaultPolicyArbiter {
|
|
|
952
1006
|
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "multipleTargetsNotSupported");
|
|
953
1007
|
}
|
|
954
1008
|
const firstTarget = arr[0];
|
|
1009
|
+
if (this.isTwinJsonPathTarget(firstTarget)) {
|
|
1010
|
+
const t = firstTarget;
|
|
1011
|
+
const resolved = this.resolveDataSourceByKey(t[DefaultPolicyArbiter._TWIN_JSONPATH_DATA_SOURCE] ?? DefaultPolicyArbiter._DATA_SOURCE_KEY, t[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION], dataSources);
|
|
1012
|
+
return {
|
|
1013
|
+
target: resolved.target,
|
|
1014
|
+
refinements: []
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
955
1017
|
if (Is.object(firstTarget)) {
|
|
956
1018
|
// Guard against unsupported ODRL asset properties
|
|
957
1019
|
if (Is.notEmpty(firstTarget.hasPolicy)) {
|
|
@@ -962,18 +1024,23 @@ export class DefaultPolicyArbiter {
|
|
|
962
1024
|
}
|
|
963
1025
|
if (Is.object(firstTarget) &&
|
|
964
1026
|
OdrlPolicyHelper.getType(firstTarget) === OdrlTypes.AssetCollection) {
|
|
965
|
-
if (
|
|
1027
|
+
if (firstTarget.source !== DefaultPolicyArbiter._TWIN_JSONPATH) {
|
|
966
1028
|
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "assetCollectionSourceNotSupported", {
|
|
967
1029
|
source: firstTarget.source ?? ""
|
|
968
1030
|
});
|
|
969
1031
|
}
|
|
1032
|
+
const ctx = firstTarget;
|
|
1033
|
+
const dataSource = ctx[DefaultPolicyArbiter._TWIN_JSONPATH_DATA_SOURCE];
|
|
1034
|
+
const sourceKey = Is.stringValue(dataSource)
|
|
1035
|
+
? dataSource
|
|
1036
|
+
: DefaultPolicyArbiter._DATA_SOURCE_KEY;
|
|
970
1037
|
let sourceLookup;
|
|
971
1038
|
try {
|
|
972
|
-
sourceLookup = this.
|
|
1039
|
+
sourceLookup = this.resolveDataSourceByKey(sourceKey, ctx[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION], dataSources);
|
|
973
1040
|
}
|
|
974
1041
|
catch {
|
|
975
1042
|
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "assetCollectionSourceNotSupported", {
|
|
976
|
-
source:
|
|
1043
|
+
source: ctx[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION] ?? ""
|
|
977
1044
|
});
|
|
978
1045
|
}
|
|
979
1046
|
return {
|
|
@@ -1054,11 +1121,18 @@ export class DefaultPolicyArbiter {
|
|
|
1054
1121
|
};
|
|
1055
1122
|
}
|
|
1056
1123
|
const regularConstraint = refinement;
|
|
1057
|
-
|
|
1124
|
+
const constraintWithExtensions = regularConstraint;
|
|
1125
|
+
const canonicalExpression = constraintWithExtensions[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION];
|
|
1126
|
+
const rewrittenConstraint = {
|
|
1058
1127
|
...regularConstraint,
|
|
1059
1128
|
leftOperand: this.rewriteOperandForDecisionTarget(regularConstraint.leftOperand, sourceTarget, itemTarget),
|
|
1060
1129
|
rightOperand: this.rewriteOperandForDecisionTarget(regularConstraint.rightOperand, sourceTarget, itemTarget)
|
|
1061
1130
|
};
|
|
1131
|
+
if (Is.stringValue(canonicalExpression)) {
|
|
1132
|
+
rewrittenConstraint[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION] =
|
|
1133
|
+
this.rewriteWildcardPath(canonicalExpression, sourceTarget, itemTarget);
|
|
1134
|
+
}
|
|
1135
|
+
return rewrittenConstraint;
|
|
1062
1136
|
}
|
|
1063
1137
|
/**
|
|
1064
1138
|
* Rewrite JSONPath-based operands from wildcard source to concrete item target.
|
|
@@ -1069,23 +1143,33 @@ export class DefaultPolicyArbiter {
|
|
|
1069
1143
|
* @internal
|
|
1070
1144
|
*/
|
|
1071
1145
|
rewriteOperandForDecisionTarget(operand, sourceTarget, itemTarget) {
|
|
1072
|
-
if (Is.stringValue(operand)) {
|
|
1073
|
-
const prefix = `${DefaultPolicyArbiter._TWIN_PREFIX_OPERATIONS}${DefaultPolicyArbiter._TWIN_PREFIX_JSONPATH}:`;
|
|
1074
|
-
if (operand.startsWith(prefix)) {
|
|
1075
|
-
const valuePath = operand.slice(prefix.length);
|
|
1076
|
-
return `${prefix}${this.rewriteWildcardPath(valuePath, sourceTarget, itemTarget)}`;
|
|
1077
|
-
}
|
|
1078
|
-
return operand;
|
|
1079
|
-
}
|
|
1080
1146
|
if (Is.object(operand)) {
|
|
1081
|
-
const typedOperand = {
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1147
|
+
const typedOperand = {
|
|
1148
|
+
...operand
|
|
1149
|
+
};
|
|
1150
|
+
if (this.isTwinJsonPathOperandType(typedOperand["@type"])) {
|
|
1151
|
+
if (Is.stringValue(typedOperand["@value"])) {
|
|
1152
|
+
typedOperand["@value"] = this.rewriteWildcardPath(typedOperand["@value"], sourceTarget, itemTarget);
|
|
1153
|
+
}
|
|
1154
|
+
const canonicalExpression = typedOperand[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION];
|
|
1155
|
+
if (Is.stringValue(canonicalExpression)) {
|
|
1156
|
+
typedOperand[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION] = this.rewriteWildcardPath(canonicalExpression, sourceTarget, itemTarget);
|
|
1157
|
+
}
|
|
1086
1158
|
}
|
|
1087
1159
|
return typedOperand;
|
|
1088
1160
|
}
|
|
1161
|
+
// Legacy string form: "twin:information:$.foo". Extract the prefix, rewrite the
|
|
1162
|
+
// JSONPath expression to scope to the per-item target, then re-assemble. Without
|
|
1163
|
+
// this, the leftOperand stays at the wildcard
|
|
1164
|
+
// `$.itemList.itemListElement[*].unloadingLocation.id` for every item, returning
|
|
1165
|
+
// the full array of all ids per check — so all items pass the equality test.
|
|
1166
|
+
if (Is.stringValue(operand) &&
|
|
1167
|
+
operand.startsWith(`twin:${DefaultPolicyArbiter._INFORMATION_SOURCE_KEY}:`)) {
|
|
1168
|
+
const prefix = `twin:${DefaultPolicyArbiter._INFORMATION_SOURCE_KEY}:`;
|
|
1169
|
+
const expression = operand.slice(prefix.length);
|
|
1170
|
+
const rewritten = this.rewriteWildcardPath(expression, sourceTarget, itemTarget);
|
|
1171
|
+
return `${prefix}${rewritten}`;
|
|
1172
|
+
}
|
|
1089
1173
|
return operand;
|
|
1090
1174
|
}
|
|
1091
1175
|
/**
|
|
@@ -1150,8 +1234,8 @@ export class DefaultPolicyArbiter {
|
|
|
1150
1234
|
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "constraintStatusNotSupported");
|
|
1151
1235
|
}
|
|
1152
1236
|
// Evaluate the main constraint condition
|
|
1153
|
-
const leftValue = this.calculateOperandValue(regularConstraint.leftOperand, dataSources);
|
|
1154
|
-
const rightValue = this.calculateOperandValue(regularConstraint.rightOperand, dataSources);
|
|
1237
|
+
const leftValue = this.calculateOperandValue(regularConstraint.leftOperand, dataSources, regularConstraint);
|
|
1238
|
+
const rightValue = this.calculateOperandValue(regularConstraint.rightOperand, dataSources, regularConstraint);
|
|
1155
1239
|
const mainSatisfied = this.evaluateOperator(regularConstraint.operator, leftValue, rightValue);
|
|
1156
1240
|
// If main constraint is not satisfied, the overall constraint fails
|
|
1157
1241
|
return mainSatisfied;
|
|
@@ -1276,27 +1360,24 @@ export class DefaultPolicyArbiter {
|
|
|
1276
1360
|
* @internal
|
|
1277
1361
|
*/
|
|
1278
1362
|
tryResolveOperandLookup(operandTypeOrValue, operandValue, dataSources) {
|
|
1279
|
-
let
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1363
|
+
let sourceKey = this.normalizeTwinJsonPathOperandAlias(operandTypeOrValue);
|
|
1364
|
+
let value = operandValue;
|
|
1365
|
+
// Combined form: operandTypeOrValue is a full "<prefix>:<expression>" string
|
|
1366
|
+
// like "twin:jsonPath:$.foo" rather than the canonical separation of @type +
|
|
1367
|
+
// @value/expression. Detect by walking the registered datasource keys for a prefix
|
|
1368
|
+
// match; on hit, split into key + expression so resolveDataSourceByKey can evaluate.
|
|
1369
|
+
if (!dataSources[sourceKey]) {
|
|
1370
|
+
const matchingKey = Object.keys(dataSources).find(k => sourceKey.startsWith(`${k}:`));
|
|
1371
|
+
if (matchingKey) {
|
|
1372
|
+
value = sourceKey.slice(matchingKey.length + 1);
|
|
1373
|
+
sourceKey = matchingKey;
|
|
1283
1374
|
}
|
|
1284
|
-
lookupTargetId = `${operandTypeOrValue}:${operandValue}`;
|
|
1285
|
-
}
|
|
1286
|
-
else if (operandTypeOrValue.includes(":")) {
|
|
1287
|
-
lookupTargetId = operandTypeOrValue;
|
|
1288
1375
|
}
|
|
1289
|
-
|
|
1376
|
+
if (!dataSources[sourceKey] || !Is.stringValue(value)) {
|
|
1290
1377
|
return undefined;
|
|
1291
1378
|
}
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
const resolved = this.tryResolveTargetDataSource(lookupTargetId, dataSources);
|
|
1295
|
-
return {
|
|
1296
|
-
source: resolved.source,
|
|
1297
|
-
jsonPath: resolved.target
|
|
1298
|
-
};
|
|
1299
|
-
}
|
|
1379
|
+
const resolved = this.resolveDataSourceByKey(sourceKey, value, dataSources);
|
|
1380
|
+
return { source: resolved.source, jsonPath: resolved.target };
|
|
1300
1381
|
}
|
|
1301
1382
|
/**
|
|
1302
1383
|
* Calculate an operand value.
|
|
@@ -1305,24 +1386,40 @@ export class DefaultPolicyArbiter {
|
|
|
1305
1386
|
* @returns The resolved operand value.
|
|
1306
1387
|
* @internal
|
|
1307
1388
|
*/
|
|
1308
|
-
calculateOperandValue(operand, dataSources) {
|
|
1309
|
-
// Treat prefixed operands as selectors against a namespaced source dictionary.
|
|
1310
|
-
// Examples: twin:jsonpath:$.field, twin:information:$.credentials.level
|
|
1389
|
+
calculateOperandValue(operand, dataSources, constraint) {
|
|
1311
1390
|
let jsonPath;
|
|
1312
1391
|
let operandRoot;
|
|
1313
1392
|
if (Is.stringValue(operand)) {
|
|
1314
|
-
const
|
|
1393
|
+
const expression = this.extractJsonPathExpressionFromConstraint(constraint, operand);
|
|
1394
|
+
let resolvedOperand = operand;
|
|
1395
|
+
if (operand === DefaultPolicyArbiter._TWIN_JSONPATH &&
|
|
1396
|
+
Is.object(constraint)) {
|
|
1397
|
+
const dataSourceOverride = constraint[DefaultPolicyArbiter._TWIN_JSONPATH_DATA_SOURCE];
|
|
1398
|
+
if (Is.stringValue(dataSourceOverride)) {
|
|
1399
|
+
resolvedOperand = dataSourceOverride;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
const lookup = this.tryResolveOperandLookup(resolvedOperand, expression ?? operand, dataSources);
|
|
1315
1403
|
if (lookup) {
|
|
1316
1404
|
jsonPath = lookup.jsonPath;
|
|
1317
1405
|
operandRoot = lookup.source;
|
|
1318
1406
|
}
|
|
1319
1407
|
}
|
|
1320
1408
|
else if (Is.object(operand)) {
|
|
1409
|
+
const typedOperand = operand;
|
|
1321
1410
|
// Is this an object { "@value": "18", "@type": "xsd:integer" } ?
|
|
1322
|
-
const value =
|
|
1323
|
-
|
|
1411
|
+
const value = this.extractJsonPathExpressionFromTypedOperand(typedOperand) ??
|
|
1412
|
+
typedOperand["@value"];
|
|
1413
|
+
const type = typedOperand["@type"];
|
|
1324
1414
|
if (Is.stringValue(type)) {
|
|
1325
|
-
|
|
1415
|
+
let resolvedType = type;
|
|
1416
|
+
if (this.isTwinJsonPathOperandType(type)) {
|
|
1417
|
+
const dataSourceOverride = typedOperand[DefaultPolicyArbiter._TWIN_JSONPATH_DATA_SOURCE];
|
|
1418
|
+
if (Is.stringValue(dataSourceOverride)) {
|
|
1419
|
+
resolvedType = dataSourceOverride;
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
const lookup = this.tryResolveOperandLookup(resolvedType, value, dataSources);
|
|
1326
1423
|
if (lookup) {
|
|
1327
1424
|
jsonPath = lookup.jsonPath;
|
|
1328
1425
|
operandRoot = lookup.source;
|
|
@@ -1352,6 +1449,89 @@ export class DefaultPolicyArbiter {
|
|
|
1352
1449
|
// Not JSON Path or object value so return as is
|
|
1353
1450
|
return operand;
|
|
1354
1451
|
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Determine if a target object uses the canonical twin:jsonPath object format.
|
|
1454
|
+
* @param target The target value.
|
|
1455
|
+
* @returns True if the target is a canonical twin:jsonPath object.
|
|
1456
|
+
* @internal
|
|
1457
|
+
*/
|
|
1458
|
+
isTwinJsonPathTarget(target) {
|
|
1459
|
+
return Is.object(target) && this.isTwinJsonPathOperandType(OdrlPolicyHelper.getType(target));
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Determine if the operand type is a jsonPath namespace.
|
|
1463
|
+
* @param type The operand type.
|
|
1464
|
+
* @returns True if the type is twin:jsonPath.
|
|
1465
|
+
* @internal
|
|
1466
|
+
*/
|
|
1467
|
+
isTwinJsonPathOperandType(type) {
|
|
1468
|
+
return type === DefaultPolicyArbiter._TWIN_JSONPATH;
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Normalize canonical jsonPath alias to the legacy jsonpath namespace key.
|
|
1472
|
+
* @param operandTypeOrValue The raw operand type or value.
|
|
1473
|
+
* @returns The normalized operand type/value.
|
|
1474
|
+
* @internal
|
|
1475
|
+
*/
|
|
1476
|
+
normalizeTwinJsonPathOperandAlias(operandTypeOrValue) {
|
|
1477
|
+
if (operandTypeOrValue === DefaultPolicyArbiter._TWIN_JSONPATH ||
|
|
1478
|
+
operandTypeOrValue.startsWith(`${DefaultPolicyArbiter._TWIN_JSONPATH}:`)) {
|
|
1479
|
+
const suffix = operandTypeOrValue.slice(DefaultPolicyArbiter._TWIN_JSONPATH.length);
|
|
1480
|
+
return `${DefaultPolicyArbiter._DATA_SOURCE_KEY}${suffix}`;
|
|
1481
|
+
}
|
|
1482
|
+
return operandTypeOrValue;
|
|
1483
|
+
}
|
|
1484
|
+
/**
|
|
1485
|
+
* Extract canonical jsonPath expression from typed operand object.
|
|
1486
|
+
* @param operand The typed operand.
|
|
1487
|
+
* @returns The jsonPath expression if present.
|
|
1488
|
+
* @internal
|
|
1489
|
+
*/
|
|
1490
|
+
extractJsonPathExpressionFromTypedOperand(operand) {
|
|
1491
|
+
if (!this.isTwinJsonPathOperandType(operand["@type"])) {
|
|
1492
|
+
return undefined;
|
|
1493
|
+
}
|
|
1494
|
+
const expression = operand[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION];
|
|
1495
|
+
if (Is.stringValue(expression)) {
|
|
1496
|
+
return expression;
|
|
1497
|
+
}
|
|
1498
|
+
const type = operand["@type"];
|
|
1499
|
+
if (type === DefaultPolicyArbiter._TWIN_JSONPATH) {
|
|
1500
|
+
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "jsonPathExpressionMissing", {
|
|
1501
|
+
operand: "rightOperand"
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
/**
|
|
1506
|
+
* Extract canonical jsonPath expression from constraint for leftOperand aliases.
|
|
1507
|
+
* @param constraint The constraint containing the left operand.
|
|
1508
|
+
* @param leftOperand The left operand.
|
|
1509
|
+
* @returns The expression if canonical form is used.
|
|
1510
|
+
* @internal
|
|
1511
|
+
*/
|
|
1512
|
+
extractJsonPathExpressionFromConstraint(constraint, leftOperand) {
|
|
1513
|
+
if (!Is.object(constraint)) {
|
|
1514
|
+
return undefined;
|
|
1515
|
+
}
|
|
1516
|
+
if (constraint.leftOperand !== leftOperand) {
|
|
1517
|
+
return undefined;
|
|
1518
|
+
}
|
|
1519
|
+
if (leftOperand.startsWith(`${DefaultPolicyArbiter._TWIN_JSONPATH}:`)) {
|
|
1520
|
+
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "jsonPathExpressionMissing", {
|
|
1521
|
+
operand: "leftOperand"
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
if (leftOperand !== DefaultPolicyArbiter._TWIN_JSONPATH) {
|
|
1525
|
+
return undefined;
|
|
1526
|
+
}
|
|
1527
|
+
const expression = constraint[DefaultPolicyArbiter._TWIN_JSONPATH_EXPRESSION];
|
|
1528
|
+
if (Is.stringValue(expression)) {
|
|
1529
|
+
return expression;
|
|
1530
|
+
}
|
|
1531
|
+
throw new GeneralError(DefaultPolicyArbiter.CLASS_NAME, "jsonPathExpressionMissing", {
|
|
1532
|
+
operand: "leftOperand"
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1355
1535
|
/**
|
|
1356
1536
|
* Evaluate an ODRL operator against resolved operands.
|
|
1357
1537
|
* @param operator The operator.
|