@naylence/runtime 0.3.21 → 0.4.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 (85) hide show
  1. package/dist/browser/index.cjs +3144 -1307
  2. package/dist/browser/index.mjs +3116 -1301
  3. package/dist/cjs/naylence/fame/factory-manifest.js +6 -0
  4. package/dist/cjs/naylence/fame/node/node-event-listener.js +4 -0
  5. package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer-factory.js +147 -0
  6. package/dist/cjs/naylence/fame/security/auth/default-policy-authorizer.js +291 -0
  7. package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
  8. package/dist/cjs/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
  9. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-definition.js +60 -0
  10. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-factory.js +35 -0
  11. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +35 -0
  12. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy-source.js +2 -0
  13. package/dist/cjs/naylence/fame/security/auth/policy/authorization-policy.js +2 -0
  14. package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +99 -0
  15. package/dist/cjs/naylence/fame/security/auth/policy/basic-authorization-policy.js +449 -0
  16. package/dist/cjs/naylence/fame/security/auth/policy/index.js +40 -0
  17. package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +101 -0
  18. package/dist/cjs/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +164 -0
  19. package/dist/cjs/naylence/fame/security/auth/policy/pattern-matcher.js +195 -0
  20. package/dist/cjs/naylence/fame/security/auth/policy/scope-matcher.js +169 -0
  21. package/dist/cjs/naylence/fame/security/auth/policy-authorizer.js +2 -0
  22. package/dist/cjs/naylence/fame/security/default-security-manager.js +94 -0
  23. package/dist/cjs/naylence/fame/security/index.js +3 -0
  24. package/dist/cjs/naylence/fame/security/node-security-profile-factory.js +3 -1
  25. package/dist/cjs/naylence/fame/sentinel/router.js +67 -1
  26. package/dist/cjs/naylence/fame/sentinel/sentinel.js +46 -2
  27. package/dist/cjs/naylence/fame/util/register-runtime-factories.js +2 -0
  28. package/dist/cjs/version.js +2 -2
  29. package/dist/esm/naylence/fame/factory-manifest.js +6 -0
  30. package/dist/esm/naylence/fame/node/node-event-listener.js +4 -0
  31. package/dist/esm/naylence/fame/security/auth/default-policy-authorizer-factory.js +110 -0
  32. package/dist/esm/naylence/fame/security/auth/default-policy-authorizer.js +287 -0
  33. package/dist/esm/naylence/fame/security/auth/oauth2-authorizer-factory.js +7 -0
  34. package/dist/esm/naylence/fame/security/auth/oauth2-authorizer.js +19 -4
  35. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-definition.js +57 -0
  36. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-factory.js +31 -0
  37. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source-factory.js +31 -0
  38. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy-source.js +1 -0
  39. package/dist/esm/naylence/fame/security/auth/policy/authorization-policy.js +1 -0
  40. package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy-factory.js +62 -0
  41. package/dist/esm/naylence/fame/security/auth/policy/basic-authorization-policy.js +445 -0
  42. package/dist/esm/naylence/fame/security/auth/policy/index.js +20 -0
  43. package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.js +64 -0
  44. package/dist/esm/naylence/fame/security/auth/policy/local-file-authorization-policy-source.js +127 -0
  45. package/dist/esm/naylence/fame/security/auth/policy/pattern-matcher.js +185 -0
  46. package/dist/esm/naylence/fame/security/auth/policy/scope-matcher.js +162 -0
  47. package/dist/esm/naylence/fame/security/auth/policy-authorizer.js +1 -0
  48. package/dist/esm/naylence/fame/security/default-security-manager.js +94 -0
  49. package/dist/esm/naylence/fame/security/index.js +3 -0
  50. package/dist/esm/naylence/fame/security/node-security-profile-factory.js +2 -0
  51. package/dist/esm/naylence/fame/sentinel/router.js +64 -0
  52. package/dist/esm/naylence/fame/sentinel/sentinel.js +47 -3
  53. package/dist/esm/naylence/fame/util/register-runtime-factories.js +2 -0
  54. package/dist/esm/version.js +2 -2
  55. package/dist/node/index.cjs +3140 -1303
  56. package/dist/node/index.mjs +3116 -1301
  57. package/dist/node/node.cjs +3191 -1338
  58. package/dist/node/node.mjs +3167 -1336
  59. package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
  60. package/dist/types/naylence/fame/node/node-event-listener.d.ts +31 -0
  61. package/dist/types/naylence/fame/security/auth/authorizer.d.ts +37 -0
  62. package/dist/types/naylence/fame/security/auth/default-policy-authorizer-factory.d.ts +55 -0
  63. package/dist/types/naylence/fame/security/auth/default-policy-authorizer.d.ts +99 -0
  64. package/dist/types/naylence/fame/security/auth/oauth2-authorizer-factory.d.ts +2 -0
  65. package/dist/types/naylence/fame/security/auth/oauth2-authorizer.d.ts +2 -0
  66. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-definition.d.ts +166 -0
  67. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-factory.d.ts +38 -0
  68. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source-factory.d.ts +38 -0
  69. package/dist/types/naylence/fame/security/auth/policy/authorization-policy-source.d.ts +20 -0
  70. package/dist/types/naylence/fame/security/auth/policy/authorization-policy.d.ts +55 -0
  71. package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy-factory.d.ts +42 -0
  72. package/dist/types/naylence/fame/security/auth/policy/basic-authorization-policy.d.ts +78 -0
  73. package/dist/types/naylence/fame/security/auth/policy/index.d.ts +19 -0
  74. package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source-factory.d.ts +51 -0
  75. package/dist/types/naylence/fame/security/auth/policy/local-file-authorization-policy-source.d.ts +67 -0
  76. package/dist/types/naylence/fame/security/auth/policy/pattern-matcher.d.ts +84 -0
  77. package/dist/types/naylence/fame/security/auth/policy/scope-matcher.d.ts +61 -0
  78. package/dist/types/naylence/fame/security/auth/policy-authorizer.d.ts +12 -0
  79. package/dist/types/naylence/fame/security/default-security-manager.d.ts +22 -0
  80. package/dist/types/naylence/fame/security/index.d.ts +2 -0
  81. package/dist/types/naylence/fame/security/node-security-profile-factory.d.ts +1 -0
  82. package/dist/types/naylence/fame/sentinel/router.d.ts +68 -0
  83. package/dist/types/naylence/fame/sentinel/sentinel.d.ts +16 -0
  84. package/dist/types/version.d.ts +1 -1
  85. package/package.json +1 -1
@@ -7,6 +7,7 @@ const security_policy_js_1 = require("./policy/security-policy.js");
7
7
  const envelope_security_handler_js_1 = require("../node/envelope-security-handler.js");
8
8
  const secure_channel_frame_handler_js_1 = require("../node/secure-channel-frame-handler.js");
9
9
  const key_frame_handler_js_1 = require("../sentinel/key-frame-handler.js");
10
+ const router_js_1 = require("../sentinel/router.js");
10
11
  const logging_js_1 = require("../util/logging.js");
11
12
  const util_js_1 = require("../util/util.js");
12
13
  const eddsa_signer_verifier_js_1 = require("../security/signing/eddsa-signer-verifier.js");
@@ -792,6 +793,99 @@ class DefaultSecurityManager {
792
793
  });
793
794
  return envelope;
794
795
  }
796
+ /**
797
+ * Route authorization hook - invoked after routing policy selects an action.
798
+ *
799
+ * This method provides centralized route authorization by:
800
+ * 1. Mapping the RoutingAction to an authorization action token
801
+ * 2. Calling authorizer.authorizeRoute() if available
802
+ * 3. Returning a Deny action on authorization failure (opaque on wire)
803
+ *
804
+ * @param node - The node performing the routing
805
+ * @param envelope - The envelope being routed
806
+ * @param selected - The RoutingAction selected by routing policy
807
+ * @param state - The current router state
808
+ * @param context - Optional delivery context
809
+ * @returns The action to execute (selected if authorized, Deny if denied)
810
+ */
811
+ async onRoutingActionSelected(node, envelope, selected, _state, context) {
812
+ // If no authorizer or authorizer doesn't implement authorizeRoute, allow
813
+ if (!this._authorizer) {
814
+ return selected;
815
+ }
816
+ if (typeof this._authorizer.authorizeRoute !== 'function') {
817
+ return selected;
818
+ }
819
+ // Map RoutingAction to authorization action token
820
+ const actionToken = (0, router_js_1.mapRoutingActionToAuthorizationAction)(selected);
821
+ // Terminal actions (Drop, Deny) don't need authorization
822
+ if (actionToken === null) {
823
+ return selected;
824
+ }
825
+ try {
826
+ const authResult = await this._authorizer.authorizeRoute(node, envelope, actionToken, context ?? undefined);
827
+ // undefined means allow (authorizer has no opinion)
828
+ if (authResult === undefined) {
829
+ return selected;
830
+ }
831
+ // Check authorization result
832
+ if (authResult.authorized) {
833
+ logger.debug('route_authorization_allowed', {
834
+ envp_id: envelope.id,
835
+ action: actionToken,
836
+ frame_type: envelope.frame?.type ?? null,
837
+ matched_rule: authResult.matchedRule ?? null,
838
+ });
839
+ return selected;
840
+ }
841
+ // Authorization denied - return Deny action with opaque NACK
842
+ logger.warning('route_authorization_denied_by_policy', {
843
+ envp_id: envelope.id,
844
+ action: actionToken,
845
+ frame_type: envelope.frame?.type ?? null,
846
+ origin_type: context?.originType ?? null,
847
+ to: envelope.to?.toString() ?? null,
848
+ denial_reason: authResult.denialReason ?? 'policy_denied',
849
+ matched_rule: authResult.matchedRule ?? null,
850
+ });
851
+ // Determine disclosure mode from configuration
852
+ const disclosure = this.getNackDisclosureMode();
853
+ return new router_js_1.Deny({
854
+ internalReason: authResult.denialReason ?? 'unauthorized_route',
855
+ deniedAction: actionToken,
856
+ matchedRule: authResult.matchedRule,
857
+ disclosure,
858
+ context: {
859
+ frame_type: envelope.frame?.type ?? null,
860
+ origin_type: context?.originType ?? null,
861
+ },
862
+ });
863
+ }
864
+ catch (error) {
865
+ logger.error('route_authorization_error', {
866
+ envp_id: envelope.id,
867
+ action: actionToken,
868
+ error: error instanceof Error ? error.message : String(error),
869
+ });
870
+ // On error, deny by default (fail-safe)
871
+ return new router_js_1.Deny({
872
+ internalReason: 'authorization_error',
873
+ deniedAction: actionToken,
874
+ disclosure: 'opaque',
875
+ context: {
876
+ error: error instanceof Error ? error.message : String(error),
877
+ },
878
+ });
879
+ }
880
+ }
881
+ /**
882
+ * Gets the NACK disclosure mode from configuration.
883
+ * Default is 'opaque' to avoid leaking route existence.
884
+ */
885
+ getNackDisclosureMode() {
886
+ // Future: Could be made configurable via _policy or constructor options
887
+ return 'opaque';
888
+ }
795
889
  async onForwardToRoute(node, nextSegment, envelope, context) {
796
890
  logger.debug('on_forward_to_route_start', {
797
891
  envp_id: envelope.id,
@@ -4,10 +4,13 @@ exports.PROFILE_NAME_OPEN = exports.PROFILE_NAME_GATED_CALLBACK = exports.PROFIL
4
4
  const tslib_1 = require("tslib");
5
5
  tslib_1.__exportStar(require("./auth/authorizer.js"), exports);
6
6
  tslib_1.__exportStar(require("./auth/auth-identity.js"), exports);
7
+ tslib_1.__exportStar(require("./auth/policy-authorizer.js"), exports);
7
8
  var authorizer_factory_js_1 = require("./auth/authorizer-factory.js");
8
9
  Object.defineProperty(exports, "AUTHORIZER_FACTORY_BASE_TYPE", { enumerable: true, get: function () { return authorizer_factory_js_1.AUTHORIZER_FACTORY_BASE_TYPE; } });
9
10
  Object.defineProperty(exports, "AuthorizerFactory", { enumerable: true, get: function () { return authorizer_factory_js_1.AuthorizerFactory; } });
10
11
  tslib_1.__exportStar(require("./auth/auth-injection-strategy.js"), exports);
12
+ // Authorization policy exports
13
+ tslib_1.__exportStar(require("./auth/policy/index.js"), exports);
11
14
  var auth_injection_strategy_factory_js_1 = require("./auth/auth-injection-strategy-factory.js");
12
15
  Object.defineProperty(exports, "AUTH_INJECTION_STRATEGY_FACTORY_BASE_TYPE", { enumerable: true, get: function () { return auth_injection_strategy_factory_js_1.AUTH_INJECTION_STRATEGY_FACTORY_BASE_TYPE; } });
13
16
  Object.defineProperty(exports, "AuthInjectionStrategyFactory", { enumerable: true, get: function () { return auth_injection_strategy_factory_js_1.AuthInjectionStrategyFactory; } });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NodeSecurityProfileFactory = exports.FACTORY_META = exports.PROFILE_NAME_OPEN = exports.PROFILE_NAME_GATED_CALLBACK = exports.PROFILE_NAME_GATED = exports.PROFILE_NAME_OVERLAY_CALLBACK = exports.PROFILE_NAME_OVERLAY = exports.PROFILE_NAME_STRICT_OVERLAY = exports.ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = exports.ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = exports.ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = exports.ENV_VAR_HMAC_SECRET = exports.ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = exports.ENV_VAR_JWKS_URL = exports.ENV_VAR_JWT_AUDIENCE = exports.ENV_VAR_JWT_ALGORITHM = exports.ENV_VAR_JWT_TRUSTED_ISSUER = void 0;
3
+ exports.NodeSecurityProfileFactory = exports.FACTORY_META = exports.PROFILE_NAME_OPEN = exports.PROFILE_NAME_GATED_CALLBACK = exports.PROFILE_NAME_GATED = exports.PROFILE_NAME_OVERLAY_CALLBACK = exports.PROFILE_NAME_OVERLAY = exports.PROFILE_NAME_STRICT_OVERLAY = exports.ENV_VAR_TRUSTED_CLIENT_SCOPE = exports.ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = exports.ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = exports.ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = exports.ENV_VAR_HMAC_SECRET = exports.ENV_VAR_DEFAULT_ENCRYPTION_LEVEL = exports.ENV_VAR_JWKS_URL = exports.ENV_VAR_JWT_AUDIENCE = exports.ENV_VAR_JWT_ALGORITHM = exports.ENV_VAR_JWT_TRUSTED_ISSUER = void 0;
4
4
  const factory_1 = require("@naylence/factory");
5
5
  const security_manager_factory_js_1 = require("./security-manager-factory.js");
6
6
  const logging_js_1 = require("../util/logging.js");
@@ -14,6 +14,7 @@ exports.ENV_VAR_HMAC_SECRET = 'FAME_HMAC_SECRET';
14
14
  exports.ENV_VAR_JWT_REVERSE_AUTH_TRUSTED_ISSUER = 'FAME_JWT_REVERSE_AUTH_TRUSTED_ISSUER';
15
15
  exports.ENV_VAR_JWT_REVERSE_AUTH_AUDIENCE = 'FAME_JWT_REVERSE_AUTH_AUDIENCE';
16
16
  exports.ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY = 'FAME_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY';
17
+ exports.ENV_VAR_TRUSTED_CLIENT_SCOPE = 'FAME_TRUSTED_CLIENT_SCOPE';
17
18
  exports.PROFILE_NAME_STRICT_OVERLAY = 'strict-overlay';
18
19
  exports.PROFILE_NAME_OVERLAY = 'overlay';
19
20
  exports.PROFILE_NAME_OVERLAY_CALLBACK = 'overlay-callback';
@@ -250,6 +251,7 @@ const GATED_PROFILE = {
250
251
  algorithm: factory_1.Expressions.env(exports.ENV_VAR_JWT_ALGORITHM, 'RS256'),
251
252
  audience: factory_1.Expressions.env(exports.ENV_VAR_JWT_AUDIENCE),
252
253
  enforce_token_subject_node_identity: factory_1.Expressions.env(exports.ENV_VAR_ENFORCE_TOKEN_SUBJECT_NODE_IDENTITY, 'false'),
254
+ trusted_client_scope: factory_1.Expressions.env(exports.ENV_VAR_TRUSTED_CLIENT_SCOPE, 'node.trusted'),
253
255
  },
254
256
  };
255
257
  const GATED_CALLBACK_PROFILE = {
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RouterState = exports.ForwardPeer = exports.ForwardChild = exports.DeliverLocal = exports.ForwardUp = exports.Drop = void 0;
3
+ exports.RouterState = exports.Deny = exports.ForwardPeer = exports.ForwardChild = exports.DeliverLocal = exports.ForwardUp = exports.Drop = void 0;
4
+ exports.mapRoutingActionToAuthorizationAction = mapRoutingActionToAuthorizationAction;
4
5
  exports.emitDeliveryNack = emitDeliveryNack;
5
6
  const core_1 = require("@naylence/core");
6
7
  const errors_js_1 = require("../errors/errors.js");
@@ -99,6 +100,71 @@ class ForwardPeer {
99
100
  }
100
101
  }
101
102
  exports.ForwardPeer = ForwardPeer;
103
+ /**
104
+ * RoutingAction that denies an envelope due to authorization failure.
105
+ *
106
+ * Emits an opaque NO_ROUTE NACK on wire (by default) to avoid leaking
107
+ * route existence, while logging the true denial reason internally.
108
+ */
109
+ class Deny {
110
+ constructor(options) {
111
+ this.options = options;
112
+ }
113
+ async execute(envelope, router, state, context) {
114
+ const { internalReason, deniedAction, matchedRule, context: extraContext, disclosure = 'opaque', } = this.options;
115
+ // Log detailed denial internally
116
+ logger.warning('route_authorization_denied', {
117
+ envp_id: envelope.id,
118
+ frame_type: envelope.frame?.type ?? null,
119
+ to: envelope.to?.toString() ?? null,
120
+ internal_reason: internalReason,
121
+ denied_action: deniedAction ?? null,
122
+ matched_rule: matchedRule ?? null,
123
+ origin_type: context?.originType ?? null,
124
+ ...extraContext,
125
+ });
126
+ // Emit opaque NACK on wire (or verbose if configured)
127
+ const wireCode = disclosure === 'verbose' ? 'UNAUTHORIZED_ROUTE' : 'NO_ROUTE';
128
+ await emitDeliveryNack(envelope, router, state, wireCode, context ?? undefined);
129
+ }
130
+ }
131
+ exports.Deny = Deny;
132
+ /**
133
+ * Maps a RoutingAction instance to an authorization action token.
134
+ *
135
+ * This function uses instanceof checks to determine the action type,
136
+ * avoiding the need to expose action objects to the authorizer.
137
+ *
138
+ * For unknown/custom RoutingAction types, returns null. Callers should
139
+ * treat null as "deny by default" for security (unknown actions are not
140
+ * authorized).
141
+ *
142
+ * @param action - The RoutingAction instance to map
143
+ * @returns The authorization action token, or null for terminal/unknown actions
144
+ */
145
+ function mapRoutingActionToAuthorizationAction(action) {
146
+ if (action instanceof ForwardUp) {
147
+ return 'ForwardUpstream';
148
+ }
149
+ if (action instanceof ForwardChild) {
150
+ return 'ForwardDownstream';
151
+ }
152
+ if (action instanceof ForwardPeer) {
153
+ return 'ForwardPeer';
154
+ }
155
+ if (action instanceof DeliverLocal) {
156
+ return 'DeliverLocal';
157
+ }
158
+ // Drop and Deny are terminal actions that don't need authorization
159
+ if (action instanceof Drop || action instanceof Deny) {
160
+ return null;
161
+ }
162
+ // Unknown RoutingAction: return null, caller should deny by default
163
+ logger.warning('unknown_routing_action_for_authorization', {
164
+ action_type: action?.constructor?.name ?? 'unknown',
165
+ });
166
+ return null;
167
+ }
102
168
  class RouterState {
103
169
  constructor(options) {
104
170
  const normalized = normalizeRouterStateOptions(options);
@@ -281,8 +281,11 @@ class Sentinel extends node_js_1.FameNode {
281
281
  }
282
282
  }
283
283
  const state = this.buildRouterState();
284
- const action = await this.routingPolicy.decide(processedEnvelope, state, context);
285
- await action.execute(processedEnvelope, this, state, context);
284
+ let action = await this.routingPolicy.decide(processedEnvelope, state, context);
285
+ // Dispatch onRoutingActionSelected hook to allow authorization/replacement
286
+ // The hook must return the action to execute; null/undefined/throw => Drop
287
+ const actionToExecute = await this.dispatchRoutingActionSelected(processedEnvelope, action, state, context);
288
+ await actionToExecute.execute(processedEnvelope, this, state, context);
286
289
  }
287
290
  async forwardToRoute(nextSegment, envelope, context) {
288
291
  if (this.originMatches(context, nextSegment, core_1.DeliveryOriginType.DOWNSTREAM)) {
@@ -828,6 +831,47 @@ class Sentinel extends node_js_1.FameNode {
828
831
  });
829
832
  }
830
833
  }
834
+ /**
835
+ * Dispatches the onRoutingActionSelected event to all event listeners.
836
+ *
837
+ * This allows listeners (like DefaultSecurityManager) to authorize
838
+ * routing actions and optionally replace them with Deny actions.
839
+ *
840
+ * The hook must return the RoutingAction to execute. If a listener returns
841
+ * null, undefined, or throws, the router will execute a Drop action.
842
+ *
843
+ * @param envelope - The envelope being routed
844
+ * @param selected - The RoutingAction selected by the routing policy
845
+ * @param state - The current router state
846
+ * @param context - Optional delivery context
847
+ * @returns The RoutingAction to execute (never null/undefined)
848
+ */
849
+ async dispatchRoutingActionSelected(envelope, selected, state, context) {
850
+ let currentAction = selected;
851
+ for (const listener of this.eventListeners) {
852
+ if (typeof listener.onRoutingActionSelected !== 'function') {
853
+ continue;
854
+ }
855
+ try {
856
+ const result = await listener.onRoutingActionSelected(this, envelope, currentAction, state, context);
857
+ // null/undefined => treat as denial, execute Drop
858
+ if (result == null) {
859
+ return new router_js_1.Drop();
860
+ }
861
+ // Update current action for next listener in chain
862
+ currentAction = result;
863
+ }
864
+ catch (error) {
865
+ // Hook threw => treat as denial, execute Drop
866
+ logger.warning('routing_action_hook_error', {
867
+ envp_id: envelope.id,
868
+ error: error instanceof Error ? error.message : String(error),
869
+ });
870
+ return new router_js_1.Drop();
871
+ }
872
+ }
873
+ return currentAction;
874
+ }
831
875
  static async aserve(options = {}) {
832
876
  const { logLevel, rootConfig, config, node = null, fabric: providedFabric = null, signals = ['SIGINT', 'SIGTERM'], signal, ...fabricOptions } = options;
833
877
  const resolvedLevel = normalizeServeLogLevel(logLevel) ?? logging_js_1.LogLevel.INFO;
@@ -45,6 +45,8 @@ const NODE_ONLY_FACTORY_MODULES = new Set([
45
45
  './connector/websocket-listener-factory.js',
46
46
  './telemetry/open-telemetry-trace-emitter-factory.js',
47
47
  './security/credential/prompt-credential-provider-factory.js',
48
+ './security/auth/default-policy-authorizer-factory.js',
49
+ './security/auth/policy/local-file-authorization-policy-source-factory.js',
48
50
  ]);
49
51
  const BROWSER_ONLY_FACTORY_MODULES = new Set([
50
52
  './security/auth/oauth2-pkce-token-provider-factory.js',
@@ -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.3.21
3
+ // Generated from package.json version: 0.4.0
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.3.21';
10
+ exports.VERSION = '0.4.0';
@@ -29,6 +29,7 @@ export const MODULES = [
29
29
  "./placement/static-node-placement-strategy-factory.js",
30
30
  "./security/auth/bearer-token-header-auth-injection-strategy-factory.js",
31
31
  "./security/auth/default-authorizer-factory.js",
32
+ "./security/auth/default-policy-authorizer-factory.js",
32
33
  "./security/auth/jwks-jwt-token-verifier-factory.js",
33
34
  "./security/auth/jwt-token-issuer-factory.js",
34
35
  "./security/auth/jwt-token-verifier-factory.js",
@@ -40,6 +41,8 @@ export const MODULES = [
40
41
  "./security/auth/oauth2-authorizer-factory.js",
41
42
  "./security/auth/oauth2-client-credentials-token-provider-factory.js",
42
43
  "./security/auth/oauth2-pkce-token-provider-factory.js",
44
+ "./security/auth/policy/basic-authorization-policy-factory.js",
45
+ "./security/auth/policy/local-file-authorization-policy-source-factory.js",
43
46
  "./security/auth/query-param-auth-injection-strategy-factory.js",
44
47
  "./security/auth/shared-secret-authorizer-factory.js",
45
48
  "./security/auth/shared-secret-token-provider-factory.js",
@@ -108,6 +111,7 @@ export const MODULE_LOADERS = {
108
111
  "./placement/static-node-placement-strategy-factory.js": () => import("./placement/static-node-placement-strategy-factory.js"),
109
112
  "./security/auth/bearer-token-header-auth-injection-strategy-factory.js": () => import("./security/auth/bearer-token-header-auth-injection-strategy-factory.js"),
110
113
  "./security/auth/default-authorizer-factory.js": () => import("./security/auth/default-authorizer-factory.js"),
114
+ "./security/auth/default-policy-authorizer-factory.js": () => import(/* webpackIgnore: true */ /* @vite-ignore */ "./security/auth/default-policy-authorizer-factory.js"),
111
115
  "./security/auth/jwks-jwt-token-verifier-factory.js": () => import("./security/auth/jwks-jwt-token-verifier-factory.js"),
112
116
  "./security/auth/jwt-token-issuer-factory.js": () => import("./security/auth/jwt-token-issuer-factory.js"),
113
117
  "./security/auth/jwt-token-verifier-factory.js": () => import("./security/auth/jwt-token-verifier-factory.js"),
@@ -119,6 +123,8 @@ export const MODULE_LOADERS = {
119
123
  "./security/auth/oauth2-authorizer-factory.js": () => import("./security/auth/oauth2-authorizer-factory.js"),
120
124
  "./security/auth/oauth2-client-credentials-token-provider-factory.js": () => import("./security/auth/oauth2-client-credentials-token-provider-factory.js"),
121
125
  "./security/auth/oauth2-pkce-token-provider-factory.js": () => import("./security/auth/oauth2-pkce-token-provider-factory.js"),
126
+ "./security/auth/policy/basic-authorization-policy-factory.js": () => import("./security/auth/policy/basic-authorization-policy-factory.js"),
127
+ "./security/auth/policy/local-file-authorization-policy-source-factory.js": () => import(/* webpackIgnore: true */ /* @vite-ignore */ "./security/auth/policy/local-file-authorization-policy-source-factory.js"),
122
128
  "./security/auth/query-param-auth-injection-strategy-factory.js": () => import("./security/auth/query-param-auth-injection-strategy-factory.js"),
123
129
  "./security/auth/shared-secret-authorizer-factory.js": () => import("./security/auth/shared-secret-authorizer-factory.js"),
124
130
  "./security/auth/shared-secret-token-provider-factory.js": () => import("./security/auth/shared-secret-token-provider-factory.js"),
@@ -45,6 +45,10 @@ export class BaseNodeEventListener {
45
45
  // Default implementation passes envelope through unchanged
46
46
  return envelope;
47
47
  }
48
+ async onRoutingActionSelected(_node, _envelope, selected, _state, _context) {
49
+ // Default implementation returns the selected action unchanged
50
+ return selected;
51
+ }
48
52
  async onForwardUpstream(_node, envelope, _context) {
49
53
  // Default implementation passes envelope through unchanged
50
54
  return envelope;
@@ -0,0 +1,110 @@
1
+ import { safeImport } from '../../util/lazy-import.js';
2
+ import { AUTHORIZER_FACTORY_BASE_TYPE, AuthorizerFactory, } from './authorizer-factory.js';
3
+ import { TokenVerifierFactory, } from './token-verifier-factory.js';
4
+ import { AuthorizationPolicySourceFactory, } from './policy/authorization-policy-source-factory.js';
5
+ import { AuthorizationPolicyFactory, } from './policy/authorization-policy-factory.js';
6
+ let defaultPolicyAuthorizerModulePromise = null;
7
+ async function getDefaultPolicyAuthorizerModule() {
8
+ if (!defaultPolicyAuthorizerModulePromise) {
9
+ defaultPolicyAuthorizerModulePromise = safeImport(() => import('./default-policy-authorizer.js'), 'default-policy-authorizer');
10
+ }
11
+ return defaultPolicyAuthorizerModulePromise;
12
+ }
13
+ function normalizeConfig(config) {
14
+ if (!config) {
15
+ return {};
16
+ }
17
+ const candidate = config;
18
+ const verifierConfig = candidate.verifier ?? null;
19
+ if (verifierConfig && typeof verifierConfig !== 'object') {
20
+ throw new Error('PolicyAuthorizer verifier configuration must be an object');
21
+ }
22
+ const policyConfig = candidate.policy ?? null;
23
+ if (policyConfig && typeof policyConfig !== 'object') {
24
+ throw new Error('PolicyAuthorizer policy configuration must be an object');
25
+ }
26
+ const policySourceConfig = candidate.policySource ?? candidate.policy_source ?? null;
27
+ if (policySourceConfig && typeof policySourceConfig !== 'object') {
28
+ throw new Error('PolicyAuthorizer policySource configuration must be an object');
29
+ }
30
+ return {
31
+ verifier: verifierConfig,
32
+ policy: policyConfig,
33
+ policySource: policySourceConfig,
34
+ };
35
+ }
36
+ function isTokenVerifier(candidate) {
37
+ return Boolean(candidate && typeof candidate.verify === 'function');
38
+ }
39
+ function isAuthorizationPolicy(candidate) {
40
+ return Boolean(candidate &&
41
+ typeof candidate.evaluateRequest === 'function');
42
+ }
43
+ function isAuthorizationPolicySource(candidate) {
44
+ return Boolean(candidate &&
45
+ typeof candidate.loadPolicy === 'function');
46
+ }
47
+ /**
48
+ * Factory metadata for registration.
49
+ */
50
+ export const FACTORY_META = {
51
+ base: AUTHORIZER_FACTORY_BASE_TYPE,
52
+ key: 'PolicyAuthorizer',
53
+ };
54
+ /**
55
+ * Factory for creating DefaultPolicyAuthorizer instances.
56
+ *
57
+ * This factory uses lazy loading to avoid pulling in Node.js-specific
58
+ * code in browser environments.
59
+ */
60
+ export class DefaultPolicyAuthorizerFactory extends AuthorizerFactory {
61
+ constructor() {
62
+ super(...arguments);
63
+ this.type = 'PolicyAuthorizer';
64
+ this.isDefault = true;
65
+ }
66
+ /**
67
+ * Creates a DefaultPolicyAuthorizer from the given configuration.
68
+ *
69
+ * @param config - Configuration for the authorizer
70
+ * @param factoryArgs - Additional factory arguments:
71
+ * - TokenVerifier instance
72
+ * - AuthorizationPolicy instance
73
+ * - AuthorizationPolicySource instance
74
+ * @returns The created authorizer
75
+ */
76
+ async create(config, ...factoryArgs) {
77
+ const normalized = normalizeConfig(config);
78
+ // Resolve token verifier
79
+ let tokenVerifier = factoryArgs.find(isTokenVerifier);
80
+ if (!tokenVerifier && normalized.verifier) {
81
+ tokenVerifier = await TokenVerifierFactory.createTokenVerifier(normalized.verifier);
82
+ }
83
+ if (!tokenVerifier) {
84
+ throw new Error('PolicyAuthorizer requires a verifier configuration or instance');
85
+ }
86
+ // Resolve policy or policy source
87
+ let policy = factoryArgs.find(isAuthorizationPolicy);
88
+ let policySource = factoryArgs.find(isAuthorizationPolicySource);
89
+ // Create policy from config if not provided as argument
90
+ if (!policy && normalized.policy) {
91
+ policy = await AuthorizationPolicyFactory.createAuthorizationPolicy(normalized.policy);
92
+ }
93
+ // Create policy source from config if not provided as argument
94
+ if (!policySource && normalized.policySource) {
95
+ policySource =
96
+ await AuthorizationPolicySourceFactory.createAuthorizationPolicySource(normalized.policySource);
97
+ }
98
+ // Validate that we have either policy or policy source
99
+ if (!policy && !policySource) {
100
+ throw new Error('PolicyAuthorizer requires either a policy or policySource configuration');
101
+ }
102
+ const { DefaultPolicyAuthorizer } = await getDefaultPolicyAuthorizerModule();
103
+ return new DefaultPolicyAuthorizer({
104
+ tokenVerifier,
105
+ policy,
106
+ policySource,
107
+ });
108
+ }
109
+ }
110
+ export default DefaultPolicyAuthorizerFactory;