Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@universal-packages/dynamic-api

Package Overview
Dependencies
Maintainers
0
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@universal-packages/dynamic-api

Dynamic decoupling-adapting system

  • 1.13.3
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
1.4K
increased by18.75%
Maintainers
0
Weekly downloads
 
Created
Source

Dynamic API

npm version Testing codecov

Dynamic decoupling-adapting system, works mostly for when a system can be done in several opinionated ways and/or needs to be extended in a dynamic way, basically a dynamic API for internal systems, instead of calling concrete methods with concrete results, you called dynamic-api methods with dynamic results depending on the context.

Install

npm install @universal-packages/dynamic-api

DynamicApi

The DynamicApi class is the entry interface to load and perform all our Dynamics.

import { DynamicApi } from '@universal-packages/dynamic-api'

const dynamicApi = new DynamicApi({ dynamicsLocation: './src' })

await dynamicApi.loadDynamics()

const result = await dynamicApi.performDynamic('calculate', { fast: true })

console.log(result)

// > "I did it fast"

Options

  • debug Boolean If true the instance of this dynamic api will keep track of what is being performed into a log.

    console.log(dynamicApi.debugLog)
    
    // > [{ name: 'calculate', payload: { fast: true }, results: ['I did it fast'], hooks: { after: [AfterCalculateDynamic], before: [BeforeCalculateDynamic] } }]
    
  • dynamicsLocation Required String default: './src' Where to look up for dynamics to load.

  • namespace String When given the prefix of the file extension will be a mix of the provided namespace and the key word dynamic, ex: when name space is auth the files with the pattern file.auth-dynamic.js|ts will be loaded. If no namespace is provided the just files with the prefix dynamic will be loaded.

  • accumulate Boolean By default only the first dynamic with a given name will be performed and the retuning value will be returned to the user. When accumulate is true all dynamics with the same name will be performed and all the results will be accumulated in an array and returned to the user.

    const result = await dynamicApi.performDynamic('calculate', { fast: true })
    
    console.log(result)
    
    // > ["I did it fast", "I also did it fast"]
    

    -- modules Map When decorating dynamics you can mark them as part of a module, you need to enable modules explicitly in the dynamic api.

    import { Dynamic } from '@universal-packages/dynamic-api'
    
    @Dynamic('sub-calculations', 'extra')
    export default class CalculateDynamic {
      async perform(payload) {
        return 'I am an extra calculation'
      }
    }
    
    const dynamicApi = new DynamicApi({ modules: { 'sub-calculations': { enabled: true } } })
    const result = await dynamicApi.performDynamic('extra')
    
    console.log(result)
    
    // > 'I am an extra calculation'
    

Instance methods

performDynamic(name: string, payload: Object)

Performs a dynamic in an asynchronous way.

performDynamicSync(name: string, payload: Object)

To not waste overhead in async calls perform dynamics synchronically, they of course should implement a sync perform method.

Decorators

@Dynamic

@Dynamic(name: string, [default: boolean]) @Dynamic(module: string, name: string, [default: boolean])

Dynamics are classes as a default export, decorated with @Dynamic decorator and implementing the method perform.

import { Dynamic } from '@universal-packages/dynamic-api'

@Dynamic('calculate')
export default class CalculateDynamic {
  async perform(payload) {
    if (payload.fast) {
      return 'I did it fast'
    } else {
      return 'I was slow'
    }
  }
}

You can perform other dynamics inside your dynamics by accessing the second argument for the perform method where the dynamic api caller is shared.

import { Dynamic } from '@universal-packages/dynamic-api'

@Dynamic('calculate')
export default class CalculateDynamic {
  async perform(payload, dynamicApi) {
    if (payload.fast) {
      const speed = await dynamicApi.performDynamic('calculate-speed', { fast: true })

      return 'I did it fast like ' + speed + ' fast'
    } else {
      return 'I was slow'
    }
  }
}

The whole point of the dynamic API is to be extensible in all posable ways, to be dynamic if we will. When creating a dynamic API you may want to let he user override provided default dynamics, in order to let that happen we mark dynamics as default, if the user creates another dynamic with same name, then that dynamic will be performed instead of the default one.

import { Dynamic } from '@universal-packages/dynamic-api'

@Dynamic('calculate', true) // <-- True to be default
export default class CalculateDynamic {
  async perform(payload) {
    if (payload.fast) {
      return 'I did it fast'
    } else {
      return 'I was slow'
    }
  }
}

You can make a dynamic part of a module by providing a module name as the first argument.

import { Dynamic } from '@universal-packages/dynamic-api'

@Dynamic('sub-calculations', 'extra')
export default class CalculateDynamic {
  async perform(payload) {
    return 'I am an extra calculation'
  }
}
@DynamicHook(lifeCycle: before | after, name: string)

Hooks allows the user to perform some other tasks before and after a main dynamic is performed, for example you need to calculate something in a dynamic but need to also log that the calculation was done, instead of overriding the dynamic for your specific case you create a hook to run after the dynamic.

import { DynamicHook } from '@universal-packages/dynamic-api'

@DynamicHook('after', 'calculate')
export default class AfterCalculateDynamic {
  async perform(payload) {
    console.log('A calculation was made with:', payload)
  }
}

after hooks have the particularity of having access to the result given by the main dynamic.

import { DynamicHook } from '@universal-packages/dynamic-api'

@DynamicHook('after', 'calculate')
export default class AfterCalculateDynamic {
  async perform(payload, result) {
    console.log('A calculation was made with:', payload, 'and with result:', result)
  }
}

The same way as with dynamics you can perform other dynamics inside your dynamics hooks by accessing the second argument in before hooks and the third in after hooks for the perform method where the dynamic api caller is shared.

import { Dynamic } from '@universal-packages/dynamic-api'

@DynamicHook('before', 'calculate')
export default class BeforeCalculateDynamic {
  async perform(payload, dynamicApi) {
    console.log('about to calculate with:', payload)
    await dynamicApi.performDynamic('prepare-data')
  }
}

Events

DynamicApi is an emitter, it does not emit anything by itself but you can use it to communicate to other parts of your app what is going on in your dynamics.

import { Dynamic } from '@universal-packages/dynamic-api'

@Dynamic('calculate')
export default class CalculateDynamic {
  async perform(payload, dynamicApi) {
    dynamicApi.emit('event', 'A calculation was done')
    if (payload.fast) {
      return 'I did it fast'
    } else {
      return 'I was slow'
    }
  }
}

Typescript

This library is developed in TypeScript and shipped fully typed.

Typing dynamics

Since all here is dynamic performDynamic takes generic payloads and return generic results, if you want to type your dynamics you can always create an interface typing the payload and the result of your dynamics.

interface DynamicNames {
  calculate: {
    payload: { fast: boolean }
    result: string
  }
}

const dynamicApi = new DynamicApi<DynamicNames>({ dynamicsLocation: './src' })

// Now result is string type and performDynamic will require a payload of the specific shape
const result = dynamicApi.performDynamic('calculate', { fast: true })

Use your template names in the hooks as well

import { Dynamic } from '@universal-packages/dynamic-api'

import { DynamicNames } from './types'

@Dynamic<DynamicNames>('calculate')
export default class CalculateDynamic {}

Contributing

The development of this library happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving this library.

License

MIT licensed.

FAQs

Package last updated on 30 Nov 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc