UNPKG

@andrew_l/service-actor

Version:

Forget about passing data like trace IDs between functions.

127 lines (123 loc) 3.2 kB
'use strict'; const context = require('@andrew_l/context'); const toolkit = require('@andrew_l/toolkit'); const SYM_MARKER = Symbol(); const SYM_RAW = Symbol(); const SYM_DATA = Symbol(); const SYM_API = Symbol(); function serviceActor(factory) { const injectKey = Symbol(); let idSeq = 0; const createActor = () => { const actor = createServiceActor(); actor.traceId = `trace-${++idSeq}`; if (factory) { actor.assign(factory()); } return actor; }; const withHook = (fn, params) => { return context.withContext(function(...args) { const parentActor = context.inject(injectKey); const actor = createActor(); if (parentActor) { actor.assign(parentActor); } if (params) { actor.assign(params); } context.provide(injectKey, actor); return fn.apply(this, args); }); }; const injectHook = () => { return context.hasInjectionContext() ? context.inject(injectKey) : void 0; }; const useHok = () => { if (!context.hasInjectionContext()) { const actor2 = createActor(); context.provide(injectKey, actor2, true); return actor2; } const existed = context.inject(injectKey); if (existed) return existed; const actor = createActor(); context.provide(injectKey, actor); return actor; }; return { with: withHook, use: useHok, inject: injectHook }; } function createServiceActor() { const actor = { traceId: "", actorId: null, actorType: "unknown", [SYM_API]: { assign }, [SYM_DATA]: {}, [SYM_RAW]: null, [SYM_MARKER]: true }; const reservedKeys = new Set(Object.keys(actor)); actor[SYM_RAW] = actor; const newProxy = new Proxy(actor[SYM_DATA], { defineProperty(target, key, value) { if (key in actor) { actor[key] = value; } else { target[key] = value; } return true; }, deleteProperty(target, key) { if (key in actor) { delete actor[key]; } else { delete target[key]; } return true; }, has(target, key) { return key in actor || key in target; }, ownKeys(target) { return [...reservedKeys, ...Object.keys(target)]; }, set: function(target, key, value) { if (key in actor[SYM_API]) return false; if (key in actor) { Reflect.set(actor, key, value); } else if (toolkit.isFunction(value)) { Reflect.set(actor[SYM_API], key, value); } else { Reflect.set(target, key, value); } return true; }, get: (target, key) => { let value; if (key in actor) { value = Reflect.get(actor, key, value); } else if (key in actor[SYM_API]) { value = Reflect.get(actor[SYM_API], key, value).bind(newProxy); } else { value = Reflect.get(target, key); } return value; }, getOwnPropertyDescriptor(k) { return { enumerable: true, configurable: true }; } }); return newProxy; } function assign(params) { Object.assign(this, params); return this; } exports.serviceActor = serviceActor; //# sourceMappingURL=index.cjs.map