@@ -397,9 +397,19 @@ options.routes = [
397397
398398## Plugins
399399
400- Plugins are a way to extend registry's context allowing components to inherit custom functionalities.
400+ Plugins are a way to extend registry's context allowing components to inherit custom functionalities. They can be configured to receive component context information (name and version) when needed for enhanced security and decision-making capabilities.
401401
402- This is a plugin example:
402+ ### Plugin Structure
403+
404+ A plugin consists of two main parts:
405+
406+ - ** register** : Function called during plugin initialization
407+ - ** execute** : Function that provides the actual plugin functionality
408+ - ** context** (optional): Boolean flag to enable component context awareness
409+
410+ ### Basic Plugin Example
411+
412+ This is a basic plugin example without context awareness:
403413
404414``` js
405415// ./registry/oc-plugins/hobknob.js
@@ -418,53 +428,212 @@ module.exports.execute = function (featureName) {
418428};
419429```
420430
421- This is how to register it in a registry:
431+ ### Context-Aware Plugin Example
432+
433+ When you need to make decisions based on which component is calling the plugin, you can enable context awareness:
434+
435+ ``` js
436+ // ./registry/oc-plugins/feature-flags.js
437+ var connection,
438+ client = require (" ./feature-flags-client" );
439+
440+ module .exports .register = function (options , dependencies , next ) {
441+ client .connect (options .connectionString , function (err , conn ) {
442+ connection = conn;
443+ next ();
444+ });
445+ };
446+
447+ // With context: true, execute receives component context and returns a function
448+ module .exports .execute = function (context ) {
449+ // context contains: { name: "component-name", version: "1.2.3" }
450+ return function (featureName ) {
451+ // Validate if this component is allowed to access this feature
452+ if (
453+ context .name .startsWith (" internal/" ) &&
454+ featureName .startsWith (" public/" )
455+ ) {
456+ throw new Error (" Internal components cannot access public features" );
457+ }
458+
459+ // Log feature access for audit purposes
460+ console .log (
461+ ` Component ${ context .name } @${ context .version } accessing feature: ${ featureName} `
462+ );
463+
464+ return connection .get (featureName);
465+ };
466+ };
467+
468+ // Enable context awareness
469+ module .exports .context = true ;
470+ ```
471+
472+ ### Plugin Registration
473+
474+ This is how to register plugins in a registry:
422475
423476``` js
424477// ./registry/init.js
425- ...
478+ var oc = require ( " oc " );
426479var registry = new oc.Registry (configuration);
427480
481+ // Register a basic plugin
428482registry .register ({
429- name: ' getFeatureSwitch' ,
430- register: require (' ./oc-plugins/hobknob' ),
483+ name: " getFeatureSwitch" ,
484+ register: require (" ./oc-plugins/hobknob" ),
431485 options: {
432- connectionString: connectionString
433- }
486+ connectionString: connectionString,
487+ },
488+ });
489+
490+ // Register a context-aware plugin
491+ registry .register ({
492+ name: " getSecureFeature" ,
493+ register: require (" ./oc-plugins/feature-flags" ),
494+ options: {
495+ connectionString: connectionString,
496+ },
434497});
435- ...
436498```
437499
438- This is how to use a plugin from a component:
500+ ### Using Plugins from Components
501+
502+ Components use plugins the same way regardless of whether they have context awareness:
439503
440504``` js
441505// ./my-component/server.js
442506module .exports .data = function (context , callback ) {
443507 callback (null , {
444- variable: context .plugins .getFeatureSwitch (" AbTestHomePage" ),
508+ // Basic plugin usage
509+ basicFeature: context .plugins .getFeatureSwitch (" AbTestHomePage" ),
510+
511+ // Context-aware plugin usage (same interface)
512+ secureFeature: context .plugins .getSecureFeature (" AdminPanel" ),
445513 });
446514};
447515```
448516
449- This is how to depend on (and use) other plugins:
517+ ### When to Use Context Awareness
518+
519+ Context awareness is useful when you need to:
520+
521+ 1 . ** Security Validation** : Restrict certain components from accessing specific features
522+ 2 . ** Audit Logging** : Track which components are using which features
523+ 3 . ** Component-Specific Logic** : Provide different behavior based on component name/version
524+ 4 . ** Rate Limiting** : Apply different limits per component
525+ 5 . ** Feature Rollouts** : Enable features only for specific components or versions
526+
527+ ### Advanced Context-Aware Plugin Example
528+
529+ Here's a more sophisticated example that demonstrates multiple use cases:
450530
451531``` js
452- // ./registry/oc-plugins/hobknob .js
532+ // ./registry/oc-plugins/advanced-feature-manager .js
453533var connection,
454- client = require (" ./hobknob-client" );
534+ client = require (" ./feature-manager-client" );
535+
536+ module .exports .register = function (options , dependencies , next ) {
537+ client .connect (options .connectionString , function (err , conn ) {
538+ connection = conn;
539+ next ();
540+ });
541+ };
542+
543+ module .exports .execute = function (context ) {
544+ return function (featureName , options = {}) {
545+ // Security: Check component permissions
546+ const componentPermissions = getComponentPermissions (context .name );
547+ if (! componentPermissions .canAccess (featureName)) {
548+ throw new Error (
549+ ` Component ${ context .name } is not authorized to access ${ featureName} `
550+ );
551+ }
552+
553+ // Audit: Log all feature access
554+ logFeatureAccess ({
555+ component: context .name ,
556+ version: context .version ,
557+ feature: featureName,
558+ timestamp: new Date ().toISOString (),
559+ });
560+
561+ // Rate limiting: Apply different limits per component
562+ const rateLimit = getRateLimit (context .name , featureName);
563+ if (isRateLimited (context .name , featureName, rateLimit)) {
564+ throw new Error (
565+ ` Rate limit exceeded for ${ context .name } accessing ${ featureName} `
566+ );
567+ }
568+
569+ // Version-specific logic
570+ if (context .version .startsWith (" 2." )) {
571+ // New API for v2+ components
572+ return connection .getV2 (featureName, options);
573+ } else {
574+ // Legacy API for older components
575+ return connection .getV1 (featureName);
576+ }
577+ };
578+ };
579+
580+ module .exports .context = true ;
581+ ```
582+
583+ ### Plugin Dependencies
584+
585+ Plugins can depend on other plugins, and context awareness works with dependencies:
586+
587+ ``` js
588+ // ./registry/oc-plugins/secure-logger.js
589+ var connection,
590+ client = require (" ./logger-client" );
455591
456592module .exports .dependencies = [" log" , " otherplugin" ];
457593
458594module .exports .register = function (options , dependencies , next ) {
459- // this register function is only called after all dependencies are registered
595+ // This register function is only called after all dependencies are registered
460596 client .connect (options .connectionString , function (err , conn ) {
461597 connection = conn;
462- dependencies .log (" hobknob client initialised " );
598+ dependencies .log (" secure logger client initialized " );
463599 next ();
464600 });
465601};
466602
467- module .exports .execute = function (featureName ) {
468- return connection .get (featureName);
603+ module .exports .execute = function (context ) {
604+ return function (message , level = " info" ) {
605+ // Add component context to all log messages
606+ const enrichedMessage = {
607+ component: context .name ,
608+ version: context .version ,
609+ message: message,
610+ level: level,
611+ timestamp: new Date ().toISOString (),
612+ };
613+
614+ return connection .log (enrichedMessage);
615+ };
469616};
617+
618+ module .exports .context = true ;
619+ ```
620+
621+ ### Plugin Configuration Options
622+
623+ | Property | Type | Required | Default | Description |
624+ | ---------- | ------- | -------- | ------- | ------------------------------------------------- |
625+ | ` name ` | string | yes | - | Unique identifier for the plugin |
626+ | ` register ` | object | yes | - | Plugin module with register and execute functions |
627+ | ` options ` | object | no | ` {} ` | Configuration options passed to the plugin |
628+ | ` context ` | boolean | no | ` false ` | Enable component context awareness |
629+
630+ ### Context Object Structure
631+
632+ When ` context: true ` is set, the context object passed to the execute function contains:
633+
634+ ``` js
635+ {
636+ name: " component-name" , // The name of the component calling the plugin
637+ version: " 1.2.3" // The version of the component calling the plugin
638+ }
470639```
0 commit comments