@naylence/runtime 0.4.3 → 0.4.5

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.
@@ -525,12 +525,12 @@ async function ensureRuntimeFactoriesRegistered(registry = factory.Registry) {
525
525
  }
526
526
 
527
527
  // This file is auto-generated during build - do not edit manually
528
- // Generated from package.json version: 0.4.3
528
+ // Generated from package.json version: 0.4.5
529
529
  /**
530
530
  * The package version, injected at build time.
531
531
  * @internal
532
532
  */
533
- const VERSION = '0.4.3';
533
+ const VERSION = '0.4.5';
534
534
 
535
535
  let initialized = false;
536
536
  const runtimePlugin = {
@@ -22062,13 +22062,21 @@ function normalizeConfig$w(config) {
22062
22062
  return { profile: canonicalProfile };
22063
22063
  }
22064
22064
  function resolveProfileName$2(candidate) {
22065
- const direct = coerceProfileString$2(candidate.profile);
22065
+ let direct = coerceProfileString$2(candidate.profile);
22066
+ if (direct && factory.ExpressionEvaluator.isExpression(direct)) {
22067
+ const evaluated = factory.ExpressionEvaluator.evaluate(direct);
22068
+ direct = coerceProfileString$2(evaluated);
22069
+ }
22066
22070
  if (direct) {
22067
22071
  return direct;
22068
22072
  }
22069
22073
  const legacyKeys = ['profile_name', 'profileName'];
22070
22074
  for (const legacyKey of legacyKeys) {
22071
- const legacyValue = coerceProfileString$2(candidate[legacyKey]);
22075
+ let legacyValue = coerceProfileString$2(candidate[legacyKey]);
22076
+ if (legacyValue && factory.ExpressionEvaluator.isExpression(legacyValue)) {
22077
+ const evaluated = factory.ExpressionEvaluator.evaluate(legacyValue);
22078
+ legacyValue = coerceProfileString$2(evaluated);
22079
+ }
22072
22080
  if (legacyValue) {
22073
22081
  return legacyValue;
22074
22082
  }
@@ -22676,6 +22684,7 @@ class BasicAuthorizationPolicy {
22676
22684
  // Action must be explicitly provided; default to wildcard if omitted
22677
22685
  // for backward compatibility during transition
22678
22686
  const resolvedAction = action ?? '*';
22687
+ const resolvedActionNormalized = this.normalizeActionToken(resolvedAction) ?? resolvedAction;
22679
22688
  const address = extractAddress(envelope);
22680
22689
  const grantedScopes = extractGrantedScopes(context);
22681
22690
  const rawFrameType = envelope.frame
@@ -22685,8 +22694,8 @@ class BasicAuthorizationPolicy {
22685
22694
  : '';
22686
22695
  // Extract and normalize origin type for rule matching
22687
22696
  const rawOriginType = context?.originType;
22688
- const originTypeNormalized = typeof rawOriginType === 'string' && rawOriginType.trim().length > 0
22689
- ? rawOriginType.trim().toLowerCase()
22697
+ const originTypeNormalized = typeof rawOriginType === 'string'
22698
+ ? this.normalizeOriginTypeToken(rawOriginType) ?? undefined
22690
22699
  : undefined;
22691
22700
  const evaluationTrace = [];
22692
22701
  // Evaluate rules in order (first match wins)
@@ -22733,8 +22742,8 @@ class BasicAuthorizationPolicy {
22733
22742
  }
22734
22743
  }
22735
22744
  // Check action match
22736
- if (!rule.actions.has('*') && !rule.actions.has(resolvedAction)) {
22737
- step.expression = `action: ${resolvedAction} not in [${Array.from(rule.actions).join(', ')}]`;
22745
+ if (!rule.actions.has('*') && !rule.actions.has(resolvedActionNormalized)) {
22746
+ step.expression = `action: ${resolvedActionNormalized} not in [${Array.from(rule.actions).join(', ')}]`;
22738
22747
  step.result = false;
22739
22748
  evaluationTrace.push(step);
22740
22749
  continue;
@@ -22801,6 +22810,9 @@ class BasicAuthorizationPolicy {
22801
22810
  };
22802
22811
  }
22803
22812
  validateDefaultEffect(effect) {
22813
+ if (effect === undefined || effect === null) {
22814
+ return 'deny';
22815
+ }
22804
22816
  if (effect !== 'allow' && effect !== 'deny') {
22805
22817
  throw new Error(`Invalid default_effect: "${String(effect)}". Must be "allow" or "deny"`);
22806
22818
  }
@@ -22873,10 +22885,11 @@ class BasicAuthorizationPolicy {
22873
22885
  }
22874
22886
  // Handle single action
22875
22887
  if (typeof action === 'string') {
22876
- if (!VALID_ACTIONS.includes(action)) {
22888
+ const normalized = this.normalizeActionToken(action);
22889
+ if (!normalized) {
22877
22890
  throw new Error(`Invalid action in rule "${ruleId}": "${action}". Must be one of: ${VALID_ACTIONS.join(', ')}`);
22878
22891
  }
22879
- return new Set([action]);
22892
+ return new Set([normalized]);
22880
22893
  }
22881
22894
  // Handle array of actions
22882
22895
  if (!Array.isArray(action)) {
@@ -22890,10 +22903,11 @@ class BasicAuthorizationPolicy {
22890
22903
  if (typeof a !== 'string') {
22891
22904
  throw new Error(`Invalid action in rule "${ruleId}": all values must be strings`);
22892
22905
  }
22893
- if (!VALID_ACTIONS.includes(a)) {
22906
+ const normalized = this.normalizeActionToken(a);
22907
+ if (!normalized) {
22894
22908
  throw new Error(`Invalid action in rule "${ruleId}": "${a}". Must be one of: ${VALID_ACTIONS.join(', ')}`);
22895
22909
  }
22896
- actions.add(a);
22910
+ actions.add(normalized);
22897
22911
  }
22898
22912
  return actions;
22899
22913
  }
@@ -22996,11 +23010,12 @@ class BasicAuthorizationPolicy {
22996
23010
  }
22997
23011
  // Handle single origin type
22998
23012
  if (typeof originType === 'string') {
22999
- const normalized = originType.trim().toLowerCase();
23000
- if (!normalized) {
23013
+ const trimmed = originType.trim();
23014
+ if (!trimmed) {
23001
23015
  throw new Error(`Invalid origin_type in rule "${ruleId}": value must not be empty`);
23002
23016
  }
23003
- if (!VALID_ORIGIN_TYPES.includes(normalized)) {
23017
+ const normalized = this.normalizeOriginTypeToken(trimmed);
23018
+ if (!normalized) {
23004
23019
  throw new Error(`Invalid origin_type in rule "${ruleId}": "${originType}". Must be one of: ${VALID_ORIGIN_TYPES.join(', ')}`);
23005
23020
  }
23006
23021
  return new Set([normalized]);
@@ -23017,17 +23032,50 @@ class BasicAuthorizationPolicy {
23017
23032
  if (typeof ot !== 'string') {
23018
23033
  throw new Error(`Invalid origin_type in rule "${ruleId}": all values must be strings`);
23019
23034
  }
23020
- const normalized = ot.trim().toLowerCase();
23021
- if (!normalized) {
23035
+ const trimmed = ot.trim();
23036
+ if (!trimmed) {
23022
23037
  throw new Error(`Invalid origin_type in rule "${ruleId}": values must not be empty`);
23023
23038
  }
23024
- if (!VALID_ORIGIN_TYPES.includes(normalized)) {
23039
+ const normalized = this.normalizeOriginTypeToken(trimmed);
23040
+ if (!normalized) {
23025
23041
  throw new Error(`Invalid origin_type in rule "${ruleId}": "${ot}". Must be one of: ${VALID_ORIGIN_TYPES.join(', ')}`);
23026
23042
  }
23027
23043
  originTypes.add(normalized);
23028
23044
  }
23029
23045
  return originTypes;
23030
23046
  }
23047
+ normalizeActionToken(value) {
23048
+ const trimmed = value.trim();
23049
+ if (!trimmed) {
23050
+ return null;
23051
+ }
23052
+ if (trimmed === '*') {
23053
+ return '*';
23054
+ }
23055
+ const normalized = trimmed.replace(/[\s_-]+/g, '').toLowerCase();
23056
+ const map = {
23057
+ connect: 'Connect',
23058
+ forwardupstream: 'ForwardUpstream',
23059
+ forwarddownstream: 'ForwardDownstream',
23060
+ forwardpeer: 'ForwardPeer',
23061
+ deliverlocal: 'DeliverLocal',
23062
+ };
23063
+ return map[normalized] ?? null;
23064
+ }
23065
+ normalizeOriginTypeToken(value) {
23066
+ const trimmed = value.trim();
23067
+ if (!trimmed) {
23068
+ return null;
23069
+ }
23070
+ const normalized = trimmed.replace(/[\s_-]+/g, '').toLowerCase();
23071
+ const map = {
23072
+ downstream: 'downstream',
23073
+ upstream: 'upstream',
23074
+ peer: 'peer',
23075
+ local: 'local',
23076
+ };
23077
+ return map[normalized] ?? null;
23078
+ }
23031
23079
  }
23032
23080
 
23033
23081
  var basicAuthorizationPolicy = /*#__PURE__*/Object.freeze({
@@ -42776,16 +42824,22 @@ class LocalFileAuthorizationPolicySource {
42776
42824
  const factoryConfig = this.policyFactoryConfig ?? policyDefinition;
42777
42825
  // Ensure we have a type field for the factory
42778
42826
  if (!('type' in factoryConfig) || typeof factoryConfig.type !== 'string') {
42779
- throw new Error(`Policy definition at ${this.path} must have a 'type' field, ` +
42780
- `or policyFactory config must be provided`);
42827
+ logger$1.warning('policy_type_missing_defaulting_to_basic', {
42828
+ path: this.path,
42829
+ });
42830
+ factoryConfig.type =
42831
+ 'BasicAuthorizationPolicy';
42781
42832
  }
42782
42833
  // Build the factory config with the policy definition
42783
42834
  // The file content IS the policy definition, so we extract the type
42784
42835
  // and wrap the remaining content as the policyDefinition
42785
- const { type, ...restOfFile } = policyDefinition;
42836
+ const { type: fileType, ...restOfFile } = policyDefinition;
42837
+ const resolvedType = typeof fileType === 'string' && fileType.trim().length > 0
42838
+ ? fileType
42839
+ : factoryConfig.type;
42786
42840
  const mergedConfig = this.policyFactoryConfig != null
42787
42841
  ? { ...this.policyFactoryConfig, policyDefinition }
42788
- : { type: factoryConfig.type, policyDefinition: restOfFile };
42842
+ : { type: resolvedType, policyDefinition: restOfFile };
42789
42843
  // Create the policy using the factory system
42790
42844
  const policy = await AuthorizationPolicyFactory.createAuthorizationPolicy(mergedConfig);
42791
42845
  if (!policy) {
@@ -1,7 +1,7 @@
1
1
  import { parseAddressComponents, FlowFlags, FameAddress, DEFAULT_POLLING_TIMEOUT_MS, extractEnvelopeAndContext, createChannelMessage, generateId, createFameEnvelope, parseAddress, formatAddress, formatAddressFromComponents, FameResponseType, localDeliveryContext, Binding, DeliveryOriginType, makeResponse, isFameMessageResponse, parseRequest, makeRequest, DEFAULT_INVOKE_TIMEOUT_MILLIS, parseResponse, ConnectorState, ConnectorStateUtils, FameFabric, isFameMessageService, isFameRPCService, FameServiceProxy, generateIdAsync, snakeToCamelObject, getDefaultFameConfigResolver, setDefaultFameConfigResolver, SigningMaterial, AuthorizationContextSchema, FameDeliveryContextSchema, SecurityContextSchema, withFabric, FameEnvelopeSchema, deserializeEnvelope, FameChannelMessage, SINK_CAPABILITY, FameFabricFactory, serializeEnvelope, createAuthorizationContext } from '@naylence/core';
2
2
  export * from '@naylence/core';
3
3
  import { z, ZodError } from 'zod';
4
- import { Registry, AbstractResourceFactory, createResource as createResource$1, createDefaultResource, registerFactory, Expressions, ExtensionManager, ExpressionEvaluationPolicy, configValidator } from '@naylence/factory';
4
+ import { Registry, AbstractResourceFactory, createResource as createResource$1, createDefaultResource, registerFactory, Expressions, ExtensionManager, ExpressionEvaluationPolicy, ExpressionEvaluator, configValidator } from '@naylence/factory';
5
5
  import { sign, hashes, verify } from '@noble/ed25519';
6
6
  import { sha256, sha512 } from '@noble/hashes/sha2.js';
7
7
  import { chacha20poly1305 } from '@noble/ciphers/chacha.js';
@@ -523,12 +523,12 @@ async function ensureRuntimeFactoriesRegistered(registry = Registry) {
523
523
  }
524
524
 
525
525
  // This file is auto-generated during build - do not edit manually
526
- // Generated from package.json version: 0.4.3
526
+ // Generated from package.json version: 0.4.5
527
527
  /**
528
528
  * The package version, injected at build time.
529
529
  * @internal
530
530
  */
531
- const VERSION = '0.4.3';
531
+ const VERSION = '0.4.5';
532
532
 
533
533
  let initialized = false;
534
534
  const runtimePlugin = {
@@ -22060,13 +22060,21 @@ function normalizeConfig$w(config) {
22060
22060
  return { profile: canonicalProfile };
22061
22061
  }
22062
22062
  function resolveProfileName$2(candidate) {
22063
- const direct = coerceProfileString$2(candidate.profile);
22063
+ let direct = coerceProfileString$2(candidate.profile);
22064
+ if (direct && ExpressionEvaluator.isExpression(direct)) {
22065
+ const evaluated = ExpressionEvaluator.evaluate(direct);
22066
+ direct = coerceProfileString$2(evaluated);
22067
+ }
22064
22068
  if (direct) {
22065
22069
  return direct;
22066
22070
  }
22067
22071
  const legacyKeys = ['profile_name', 'profileName'];
22068
22072
  for (const legacyKey of legacyKeys) {
22069
- const legacyValue = coerceProfileString$2(candidate[legacyKey]);
22073
+ let legacyValue = coerceProfileString$2(candidate[legacyKey]);
22074
+ if (legacyValue && ExpressionEvaluator.isExpression(legacyValue)) {
22075
+ const evaluated = ExpressionEvaluator.evaluate(legacyValue);
22076
+ legacyValue = coerceProfileString$2(evaluated);
22077
+ }
22070
22078
  if (legacyValue) {
22071
22079
  return legacyValue;
22072
22080
  }
@@ -22674,6 +22682,7 @@ class BasicAuthorizationPolicy {
22674
22682
  // Action must be explicitly provided; default to wildcard if omitted
22675
22683
  // for backward compatibility during transition
22676
22684
  const resolvedAction = action ?? '*';
22685
+ const resolvedActionNormalized = this.normalizeActionToken(resolvedAction) ?? resolvedAction;
22677
22686
  const address = extractAddress(envelope);
22678
22687
  const grantedScopes = extractGrantedScopes(context);
22679
22688
  const rawFrameType = envelope.frame
@@ -22683,8 +22692,8 @@ class BasicAuthorizationPolicy {
22683
22692
  : '';
22684
22693
  // Extract and normalize origin type for rule matching
22685
22694
  const rawOriginType = context?.originType;
22686
- const originTypeNormalized = typeof rawOriginType === 'string' && rawOriginType.trim().length > 0
22687
- ? rawOriginType.trim().toLowerCase()
22695
+ const originTypeNormalized = typeof rawOriginType === 'string'
22696
+ ? this.normalizeOriginTypeToken(rawOriginType) ?? undefined
22688
22697
  : undefined;
22689
22698
  const evaluationTrace = [];
22690
22699
  // Evaluate rules in order (first match wins)
@@ -22731,8 +22740,8 @@ class BasicAuthorizationPolicy {
22731
22740
  }
22732
22741
  }
22733
22742
  // Check action match
22734
- if (!rule.actions.has('*') && !rule.actions.has(resolvedAction)) {
22735
- step.expression = `action: ${resolvedAction} not in [${Array.from(rule.actions).join(', ')}]`;
22743
+ if (!rule.actions.has('*') && !rule.actions.has(resolvedActionNormalized)) {
22744
+ step.expression = `action: ${resolvedActionNormalized} not in [${Array.from(rule.actions).join(', ')}]`;
22736
22745
  step.result = false;
22737
22746
  evaluationTrace.push(step);
22738
22747
  continue;
@@ -22799,6 +22808,9 @@ class BasicAuthorizationPolicy {
22799
22808
  };
22800
22809
  }
22801
22810
  validateDefaultEffect(effect) {
22811
+ if (effect === undefined || effect === null) {
22812
+ return 'deny';
22813
+ }
22802
22814
  if (effect !== 'allow' && effect !== 'deny') {
22803
22815
  throw new Error(`Invalid default_effect: "${String(effect)}". Must be "allow" or "deny"`);
22804
22816
  }
@@ -22871,10 +22883,11 @@ class BasicAuthorizationPolicy {
22871
22883
  }
22872
22884
  // Handle single action
22873
22885
  if (typeof action === 'string') {
22874
- if (!VALID_ACTIONS.includes(action)) {
22886
+ const normalized = this.normalizeActionToken(action);
22887
+ if (!normalized) {
22875
22888
  throw new Error(`Invalid action in rule "${ruleId}": "${action}". Must be one of: ${VALID_ACTIONS.join(', ')}`);
22876
22889
  }
22877
- return new Set([action]);
22890
+ return new Set([normalized]);
22878
22891
  }
22879
22892
  // Handle array of actions
22880
22893
  if (!Array.isArray(action)) {
@@ -22888,10 +22901,11 @@ class BasicAuthorizationPolicy {
22888
22901
  if (typeof a !== 'string') {
22889
22902
  throw new Error(`Invalid action in rule "${ruleId}": all values must be strings`);
22890
22903
  }
22891
- if (!VALID_ACTIONS.includes(a)) {
22904
+ const normalized = this.normalizeActionToken(a);
22905
+ if (!normalized) {
22892
22906
  throw new Error(`Invalid action in rule "${ruleId}": "${a}". Must be one of: ${VALID_ACTIONS.join(', ')}`);
22893
22907
  }
22894
- actions.add(a);
22908
+ actions.add(normalized);
22895
22909
  }
22896
22910
  return actions;
22897
22911
  }
@@ -22994,11 +23008,12 @@ class BasicAuthorizationPolicy {
22994
23008
  }
22995
23009
  // Handle single origin type
22996
23010
  if (typeof originType === 'string') {
22997
- const normalized = originType.trim().toLowerCase();
22998
- if (!normalized) {
23011
+ const trimmed = originType.trim();
23012
+ if (!trimmed) {
22999
23013
  throw new Error(`Invalid origin_type in rule "${ruleId}": value must not be empty`);
23000
23014
  }
23001
- if (!VALID_ORIGIN_TYPES.includes(normalized)) {
23015
+ const normalized = this.normalizeOriginTypeToken(trimmed);
23016
+ if (!normalized) {
23002
23017
  throw new Error(`Invalid origin_type in rule "${ruleId}": "${originType}". Must be one of: ${VALID_ORIGIN_TYPES.join(', ')}`);
23003
23018
  }
23004
23019
  return new Set([normalized]);
@@ -23015,17 +23030,50 @@ class BasicAuthorizationPolicy {
23015
23030
  if (typeof ot !== 'string') {
23016
23031
  throw new Error(`Invalid origin_type in rule "${ruleId}": all values must be strings`);
23017
23032
  }
23018
- const normalized = ot.trim().toLowerCase();
23019
- if (!normalized) {
23033
+ const trimmed = ot.trim();
23034
+ if (!trimmed) {
23020
23035
  throw new Error(`Invalid origin_type in rule "${ruleId}": values must not be empty`);
23021
23036
  }
23022
- if (!VALID_ORIGIN_TYPES.includes(normalized)) {
23037
+ const normalized = this.normalizeOriginTypeToken(trimmed);
23038
+ if (!normalized) {
23023
23039
  throw new Error(`Invalid origin_type in rule "${ruleId}": "${ot}". Must be one of: ${VALID_ORIGIN_TYPES.join(', ')}`);
23024
23040
  }
23025
23041
  originTypes.add(normalized);
23026
23042
  }
23027
23043
  return originTypes;
23028
23044
  }
23045
+ normalizeActionToken(value) {
23046
+ const trimmed = value.trim();
23047
+ if (!trimmed) {
23048
+ return null;
23049
+ }
23050
+ if (trimmed === '*') {
23051
+ return '*';
23052
+ }
23053
+ const normalized = trimmed.replace(/[\s_-]+/g, '').toLowerCase();
23054
+ const map = {
23055
+ connect: 'Connect',
23056
+ forwardupstream: 'ForwardUpstream',
23057
+ forwarddownstream: 'ForwardDownstream',
23058
+ forwardpeer: 'ForwardPeer',
23059
+ deliverlocal: 'DeliverLocal',
23060
+ };
23061
+ return map[normalized] ?? null;
23062
+ }
23063
+ normalizeOriginTypeToken(value) {
23064
+ const trimmed = value.trim();
23065
+ if (!trimmed) {
23066
+ return null;
23067
+ }
23068
+ const normalized = trimmed.replace(/[\s_-]+/g, '').toLowerCase();
23069
+ const map = {
23070
+ downstream: 'downstream',
23071
+ upstream: 'upstream',
23072
+ peer: 'peer',
23073
+ local: 'local',
23074
+ };
23075
+ return map[normalized] ?? null;
23076
+ }
23029
23077
  }
23030
23078
 
23031
23079
  var basicAuthorizationPolicy = /*#__PURE__*/Object.freeze({
@@ -42774,16 +42822,22 @@ class LocalFileAuthorizationPolicySource {
42774
42822
  const factoryConfig = this.policyFactoryConfig ?? policyDefinition;
42775
42823
  // Ensure we have a type field for the factory
42776
42824
  if (!('type' in factoryConfig) || typeof factoryConfig.type !== 'string') {
42777
- throw new Error(`Policy definition at ${this.path} must have a 'type' field, ` +
42778
- `or policyFactory config must be provided`);
42825
+ logger$1.warning('policy_type_missing_defaulting_to_basic', {
42826
+ path: this.path,
42827
+ });
42828
+ factoryConfig.type =
42829
+ 'BasicAuthorizationPolicy';
42779
42830
  }
42780
42831
  // Build the factory config with the policy definition
42781
42832
  // The file content IS the policy definition, so we extract the type
42782
42833
  // and wrap the remaining content as the policyDefinition
42783
- const { type, ...restOfFile } = policyDefinition;
42834
+ const { type: fileType, ...restOfFile } = policyDefinition;
42835
+ const resolvedType = typeof fileType === 'string' && fileType.trim().length > 0
42836
+ ? fileType
42837
+ : factoryConfig.type;
42784
42838
  const mergedConfig = this.policyFactoryConfig != null
42785
42839
  ? { ...this.policyFactoryConfig, policyDefinition }
42786
- : { type: factoryConfig.type, policyDefinition: restOfFile };
42840
+ : { type: resolvedType, policyDefinition: restOfFile };
42787
42841
  // Create the policy using the factory system
42788
42842
  const policy = await AuthorizationPolicyFactory.createAuthorizationPolicy(mergedConfig);
42789
42843
  if (!policy) {
@@ -146,13 +146,21 @@ function normalizeConfig(config) {
146
146
  return { profile: canonicalProfile };
147
147
  }
148
148
  function resolveProfileName(candidate) {
149
- const direct = coerceProfileString(candidate.profile);
149
+ let direct = coerceProfileString(candidate.profile);
150
+ if (direct && factory_1.ExpressionEvaluator.isExpression(direct)) {
151
+ const evaluated = factory_1.ExpressionEvaluator.evaluate(direct);
152
+ direct = coerceProfileString(evaluated);
153
+ }
150
154
  if (direct) {
151
155
  return direct;
152
156
  }
153
157
  const legacyKeys = ['profile_name', 'profileName'];
154
158
  for (const legacyKey of legacyKeys) {
155
- const legacyValue = coerceProfileString(candidate[legacyKey]);
159
+ let legacyValue = coerceProfileString(candidate[legacyKey]);
160
+ if (legacyValue && factory_1.ExpressionEvaluator.isExpression(legacyValue)) {
161
+ const evaluated = factory_1.ExpressionEvaluator.evaluate(legacyValue);
162
+ legacyValue = coerceProfileString(evaluated);
163
+ }
156
164
  if (legacyValue) {
157
165
  return legacyValue;
158
166
  }
@@ -93,6 +93,7 @@ class BasicAuthorizationPolicy {
93
93
  // Action must be explicitly provided; default to wildcard if omitted
94
94
  // for backward compatibility during transition
95
95
  const resolvedAction = action ?? '*';
96
+ const resolvedActionNormalized = this.normalizeActionToken(resolvedAction) ?? resolvedAction;
96
97
  const address = extractAddress(envelope);
97
98
  const grantedScopes = extractGrantedScopes(context);
98
99
  const rawFrameType = envelope.frame
@@ -102,8 +103,8 @@ class BasicAuthorizationPolicy {
102
103
  : '';
103
104
  // Extract and normalize origin type for rule matching
104
105
  const rawOriginType = context?.originType;
105
- const originTypeNormalized = typeof rawOriginType === 'string' && rawOriginType.trim().length > 0
106
- ? rawOriginType.trim().toLowerCase()
106
+ const originTypeNormalized = typeof rawOriginType === 'string'
107
+ ? this.normalizeOriginTypeToken(rawOriginType) ?? undefined
107
108
  : undefined;
108
109
  const evaluationTrace = [];
109
110
  // Evaluate rules in order (first match wins)
@@ -150,8 +151,8 @@ class BasicAuthorizationPolicy {
150
151
  }
151
152
  }
152
153
  // Check action match
153
- if (!rule.actions.has('*') && !rule.actions.has(resolvedAction)) {
154
- step.expression = `action: ${resolvedAction} not in [${Array.from(rule.actions).join(', ')}]`;
154
+ if (!rule.actions.has('*') && !rule.actions.has(resolvedActionNormalized)) {
155
+ step.expression = `action: ${resolvedActionNormalized} not in [${Array.from(rule.actions).join(', ')}]`;
155
156
  step.result = false;
156
157
  evaluationTrace.push(step);
157
158
  continue;
@@ -218,6 +219,9 @@ class BasicAuthorizationPolicy {
218
219
  };
219
220
  }
220
221
  validateDefaultEffect(effect) {
222
+ if (effect === undefined || effect === null) {
223
+ return 'deny';
224
+ }
221
225
  if (effect !== 'allow' && effect !== 'deny') {
222
226
  throw new Error(`Invalid default_effect: "${String(effect)}". Must be "allow" or "deny"`);
223
227
  }
@@ -290,10 +294,11 @@ class BasicAuthorizationPolicy {
290
294
  }
291
295
  // Handle single action
292
296
  if (typeof action === 'string') {
293
- if (!authorization_policy_definition_js_1.VALID_ACTIONS.includes(action)) {
297
+ const normalized = this.normalizeActionToken(action);
298
+ if (!normalized) {
294
299
  throw new Error(`Invalid action in rule "${ruleId}": "${action}". Must be one of: ${authorization_policy_definition_js_1.VALID_ACTIONS.join(', ')}`);
295
300
  }
296
- return new Set([action]);
301
+ return new Set([normalized]);
297
302
  }
298
303
  // Handle array of actions
299
304
  if (!Array.isArray(action)) {
@@ -307,10 +312,11 @@ class BasicAuthorizationPolicy {
307
312
  if (typeof a !== 'string') {
308
313
  throw new Error(`Invalid action in rule "${ruleId}": all values must be strings`);
309
314
  }
310
- if (!authorization_policy_definition_js_1.VALID_ACTIONS.includes(a)) {
315
+ const normalized = this.normalizeActionToken(a);
316
+ if (!normalized) {
311
317
  throw new Error(`Invalid action in rule "${ruleId}": "${a}". Must be one of: ${authorization_policy_definition_js_1.VALID_ACTIONS.join(', ')}`);
312
318
  }
313
- actions.add(a);
319
+ actions.add(normalized);
314
320
  }
315
321
  return actions;
316
322
  }
@@ -413,11 +419,12 @@ class BasicAuthorizationPolicy {
413
419
  }
414
420
  // Handle single origin type
415
421
  if (typeof originType === 'string') {
416
- const normalized = originType.trim().toLowerCase();
417
- if (!normalized) {
422
+ const trimmed = originType.trim();
423
+ if (!trimmed) {
418
424
  throw new Error(`Invalid origin_type in rule "${ruleId}": value must not be empty`);
419
425
  }
420
- if (!authorization_policy_definition_js_1.VALID_ORIGIN_TYPES.includes(normalized)) {
426
+ const normalized = this.normalizeOriginTypeToken(trimmed);
427
+ if (!normalized) {
421
428
  throw new Error(`Invalid origin_type in rule "${ruleId}": "${originType}". Must be one of: ${authorization_policy_definition_js_1.VALID_ORIGIN_TYPES.join(', ')}`);
422
429
  }
423
430
  return new Set([normalized]);
@@ -434,16 +441,49 @@ class BasicAuthorizationPolicy {
434
441
  if (typeof ot !== 'string') {
435
442
  throw new Error(`Invalid origin_type in rule "${ruleId}": all values must be strings`);
436
443
  }
437
- const normalized = ot.trim().toLowerCase();
438
- if (!normalized) {
444
+ const trimmed = ot.trim();
445
+ if (!trimmed) {
439
446
  throw new Error(`Invalid origin_type in rule "${ruleId}": values must not be empty`);
440
447
  }
441
- if (!authorization_policy_definition_js_1.VALID_ORIGIN_TYPES.includes(normalized)) {
448
+ const normalized = this.normalizeOriginTypeToken(trimmed);
449
+ if (!normalized) {
442
450
  throw new Error(`Invalid origin_type in rule "${ruleId}": "${ot}". Must be one of: ${authorization_policy_definition_js_1.VALID_ORIGIN_TYPES.join(', ')}`);
443
451
  }
444
452
  originTypes.add(normalized);
445
453
  }
446
454
  return originTypes;
447
455
  }
456
+ normalizeActionToken(value) {
457
+ const trimmed = value.trim();
458
+ if (!trimmed) {
459
+ return null;
460
+ }
461
+ if (trimmed === '*') {
462
+ return '*';
463
+ }
464
+ const normalized = trimmed.replace(/[\s_-]+/g, '').toLowerCase();
465
+ const map = {
466
+ connect: 'Connect',
467
+ forwardupstream: 'ForwardUpstream',
468
+ forwarddownstream: 'ForwardDownstream',
469
+ forwardpeer: 'ForwardPeer',
470
+ deliverlocal: 'DeliverLocal',
471
+ };
472
+ return map[normalized] ?? null;
473
+ }
474
+ normalizeOriginTypeToken(value) {
475
+ const trimmed = value.trim();
476
+ if (!trimmed) {
477
+ return null;
478
+ }
479
+ const normalized = trimmed.replace(/[\s_-]+/g, '').toLowerCase();
480
+ const map = {
481
+ downstream: 'downstream',
482
+ upstream: 'upstream',
483
+ peer: 'peer',
484
+ local: 'local',
485
+ };
486
+ return map[normalized] ?? null;
487
+ }
448
488
  }
449
489
  exports.BasicAuthorizationPolicy = BasicAuthorizationPolicy;
@@ -123,16 +123,22 @@ class LocalFileAuthorizationPolicySource {
123
123
  const factoryConfig = this.policyFactoryConfig ?? policyDefinition;
124
124
  // Ensure we have a type field for the factory
125
125
  if (!('type' in factoryConfig) || typeof factoryConfig.type !== 'string') {
126
- throw new Error(`Policy definition at ${this.path} must have a 'type' field, ` +
127
- `or policyFactory config must be provided`);
126
+ logger.warning('policy_type_missing_defaulting_to_basic', {
127
+ path: this.path,
128
+ });
129
+ factoryConfig.type =
130
+ 'BasicAuthorizationPolicy';
128
131
  }
129
132
  // Build the factory config with the policy definition
130
133
  // The file content IS the policy definition, so we extract the type
131
134
  // and wrap the remaining content as the policyDefinition
132
- const { type, ...restOfFile } = policyDefinition;
135
+ const { type: fileType, ...restOfFile } = policyDefinition;
136
+ const resolvedType = typeof fileType === 'string' && fileType.trim().length > 0
137
+ ? fileType
138
+ : factoryConfig.type;
133
139
  const mergedConfig = this.policyFactoryConfig != null
134
140
  ? { ...this.policyFactoryConfig, policyDefinition }
135
- : { type: factoryConfig.type, policyDefinition: restOfFile };
141
+ : { type: resolvedType, policyDefinition: restOfFile };
136
142
  // Create the policy using the factory system
137
143
  const policy = await authorization_policy_factory_js_1.AuthorizationPolicyFactory.createAuthorizationPolicy(mergedConfig);
138
144
  if (!policy) {
@@ -1,10 +1,10 @@
1
1
  "use strict";
2
2
  // This file is auto-generated during build - do not edit manually
3
- // Generated from package.json version: 0.4.3
3
+ // Generated from package.json version: 0.4.5
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.VERSION = void 0;
6
6
  /**
7
7
  * The package version, injected at build time.
8
8
  * @internal
9
9
  */
10
- exports.VERSION = '0.4.3';
10
+ exports.VERSION = '0.4.5';
@@ -1,4 +1,4 @@
1
- import { Expressions } from '@naylence/factory';
1
+ import { Expressions, ExpressionEvaluator } from '@naylence/factory';
2
2
  import { getLogger } from '../../util/logging.js';
3
3
  import { AUTHORIZER_FACTORY_BASE_TYPE, AuthorizerFactory, } from './authorizer-factory.js';
4
4
  const logger = getLogger('naylence.fame.security.auth.authorization_profile_factory');
@@ -142,13 +142,21 @@ function normalizeConfig(config) {
142
142
  return { profile: canonicalProfile };
143
143
  }
144
144
  function resolveProfileName(candidate) {
145
- const direct = coerceProfileString(candidate.profile);
145
+ let direct = coerceProfileString(candidate.profile);
146
+ if (direct && ExpressionEvaluator.isExpression(direct)) {
147
+ const evaluated = ExpressionEvaluator.evaluate(direct);
148
+ direct = coerceProfileString(evaluated);
149
+ }
146
150
  if (direct) {
147
151
  return direct;
148
152
  }
149
153
  const legacyKeys = ['profile_name', 'profileName'];
150
154
  for (const legacyKey of legacyKeys) {
151
- const legacyValue = coerceProfileString(candidate[legacyKey]);
155
+ let legacyValue = coerceProfileString(candidate[legacyKey]);
156
+ if (legacyValue && ExpressionEvaluator.isExpression(legacyValue)) {
157
+ const evaluated = ExpressionEvaluator.evaluate(legacyValue);
158
+ legacyValue = coerceProfileString(evaluated);
159
+ }
152
160
  if (legacyValue) {
153
161
  return legacyValue;
154
162
  }