@andrew_l/service-actor
Version:
Forget about passing data like trace IDs between functions.
1 lines • 9.57 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import {\n hasInjectionContext,\n inject,\n provide,\n withContext,\n} from '@andrew_l/context';\nimport {\n type AnyFunction,\n type OverwriteWith,\n isFunction,\n} from '@andrew_l/toolkit';\n\ntype ServiceActorInternal = {\n traceId: unknown;\n actorId: unknown;\n actorType: unknown;\n [SYM_API]: Record<PropertyKey, Function>;\n [SYM_MARKER]: boolean;\n [SYM_RAW]: any;\n [SYM_DATA]: Record<PropertyKey, unknown>;\n};\n\nexport type AnyServiceActor = {\n traceId: any;\n actorId: any;\n actorType: any;\n [x: PropertyKey]: any;\n};\n\nexport type ServiceActorData<T extends Record<PropertyKey, any> = {}> =\n OverwriteWith<\n {\n traceId: string;\n actorId: string | null;\n actorType: 'unknown' | string;\n },\n T\n >;\n\nexport type ServiceActor<T extends Record<PropertyKey, any> = {}> =\n ServiceActorData<T> & {\n assign(params: Partial<ServiceActorData<T>>): ServiceActor<T>;\n };\n\nconst SYM_MARKER = Symbol();\nconst SYM_RAW = Symbol();\nconst SYM_DATA = Symbol();\nconst SYM_API = Symbol();\n\n/**\n * Create service actor hooks\n *\n * @example\n * const { use: useServiceActor, with: withServiceActor } = serviceActor(() => ({\n * actorType: 'http-request',\n * ipAddress: '',\n * }));\n *\n * app.use((ctx, next) => {\n * return withServiceActor(\n * {\n * traceId: ctx.headers['x-request-id'],\n * ipAddress: ctx.headers['x-forwarded-for'],\n * },\n * next,\n * );\n * });\n *\n * app.get('/', () => {\n * const actor = useServiceActor();\n *\n * // { traceId: 'req_35123', actorId: null, actorType: 'http-request', ipAddress: '::' }\n * console.log(actor);\n * });\n *\n * @group Main\n */\nexport function serviceActor<T extends Record<PropertyKey, any> = {}>(\n factory?: () => T,\n): {\n /**\n * Wrap a function to execute it with service actor providers\n */\n with: <Fn extends AnyFunction>(\n fn: Fn,\n params?: Partial<ServiceActor<T>>,\n ) => Fn;\n\n /**\n * Returns the service actor instance from the current context.\n */\n inject: () => ServiceActor<T> | undefined;\n\n /**\n * Returns the service actor instance from the context, or creates and binds a new instance if none exists.\n */\n use: () => ServiceActor<T>;\n} {\n const injectKey = Symbol();\n\n let idSeq = 0;\n\n const createActor = (): AnyServiceActor => {\n const actor = createServiceActor();\n\n actor.traceId = `trace-${++idSeq}`;\n\n if (factory) {\n actor.assign(factory());\n }\n\n return actor;\n };\n\n const withHook = <Fn extends AnyFunction>(\n fn: Fn,\n params?: Partial<ServiceActor<T>>,\n ): Fn => {\n return withContext(function (this: any, ...args: any[]) {\n const parentActor = inject<ServiceActor>(injectKey);\n const actor = createActor();\n\n if (parentActor) {\n actor.assign(parentActor);\n }\n\n if (params) {\n actor.assign(params);\n }\n\n provide(injectKey, actor);\n\n return fn.apply(this, args);\n }) as Fn;\n };\n\n const injectHook = (): AnyServiceActor | undefined => {\n return hasInjectionContext() ? inject<ServiceActor>(injectKey) : undefined;\n };\n\n const useHok = (): AnyServiceActor => {\n if (!hasInjectionContext()) {\n const actor = createActor();\n provide(injectKey, actor, true);\n\n return actor;\n }\n\n const existed = inject<AnyServiceActor>(injectKey);\n\n if (existed) return existed;\n\n const actor = createActor();\n provide(injectKey, actor);\n\n return actor;\n };\n\n return { with: withHook, use: useHok as any, inject: injectHook as any };\n}\n\nfunction createServiceActor(): ServiceActor {\n const actor: ServiceActorInternal = {\n traceId: '',\n actorId: null,\n actorType: 'unknown',\n [SYM_API]: {\n assign,\n },\n [SYM_DATA]: {},\n [SYM_RAW]: null,\n [SYM_MARKER]: true,\n };\n\n const reservedKeys = new Set(Object.keys(actor));\n\n actor[SYM_RAW] = actor;\n\n const newProxy = new Proxy(actor[SYM_DATA], {\n defineProperty(target, key, value) {\n if (key in actor) {\n (actor as any)[key] = value;\n } else {\n target[key] = value;\n }\n\n return true;\n },\n deleteProperty(target, key) {\n if (key in actor) {\n delete (actor as any)[key];\n } else {\n delete target[key];\n }\n\n return true;\n },\n has(target, key) {\n return key in actor || key in target;\n },\n ownKeys(target) {\n return [...reservedKeys, ...Object.keys(target)];\n },\n set: function (target, key, value) {\n if (key in actor[SYM_API]) return false;\n\n if (key in actor) {\n Reflect.set(actor, key, value);\n } else if (isFunction(value)) {\n Reflect.set(actor[SYM_API], key, value);\n } else {\n Reflect.set(target, key, value);\n }\n\n return true;\n },\n get: (target, key) => {\n let value: any;\n\n if (key in actor) {\n value = Reflect.get(actor, key, value);\n } else if (key in actor[SYM_API]) {\n value = Reflect.get(actor[SYM_API], key, value).bind(newProxy);\n } else {\n value = Reflect.get(target, key);\n }\n\n return value;\n },\n getOwnPropertyDescriptor(k) {\n return {\n enumerable: true,\n configurable: true,\n };\n },\n });\n\n return newProxy as ServiceActor;\n}\n\nfunction assign(this: ServiceActor, params: Record<any, any>) {\n Object.assign(this, params);\n return this;\n}\n"],"names":["actor"],"mappings":"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"}