index.mjs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. function createContext(opts = {}) {
  2. let currentInstance;
  3. let isSingleton = false;
  4. const checkConflict = (instance) => {
  5. if (currentInstance && currentInstance !== instance) {
  6. throw new Error("Context conflict");
  7. }
  8. };
  9. let als;
  10. if (opts.asyncContext) {
  11. const _AsyncLocalStorage = opts.AsyncLocalStorage || globalThis.AsyncLocalStorage;
  12. if (_AsyncLocalStorage) {
  13. als = new _AsyncLocalStorage();
  14. } else {
  15. console.warn("[unctx] `AsyncLocalStorage` is not provided.");
  16. }
  17. }
  18. const _getCurrentInstance = () => {
  19. if (als) {
  20. const instance = als.getStore();
  21. if (instance !== void 0) {
  22. return instance;
  23. }
  24. }
  25. return currentInstance;
  26. };
  27. return {
  28. use: () => {
  29. const _instance = _getCurrentInstance();
  30. if (_instance === void 0) {
  31. throw new Error("Context is not available");
  32. }
  33. return _instance;
  34. },
  35. tryUse: () => {
  36. return _getCurrentInstance();
  37. },
  38. set: (instance, replace) => {
  39. if (!replace) {
  40. checkConflict(instance);
  41. }
  42. currentInstance = instance;
  43. isSingleton = true;
  44. },
  45. unset: () => {
  46. currentInstance = void 0;
  47. isSingleton = false;
  48. },
  49. call: (instance, callback) => {
  50. checkConflict(instance);
  51. currentInstance = instance;
  52. try {
  53. return als ? als.run(instance, callback) : callback();
  54. } finally {
  55. if (!isSingleton) {
  56. currentInstance = void 0;
  57. }
  58. }
  59. },
  60. async callAsync(instance, callback) {
  61. currentInstance = instance;
  62. const onRestore = () => {
  63. currentInstance = instance;
  64. };
  65. const onLeave = () => currentInstance === instance ? onRestore : void 0;
  66. asyncHandlers.add(onLeave);
  67. try {
  68. const r = als ? als.run(instance, callback) : callback();
  69. if (!isSingleton) {
  70. currentInstance = void 0;
  71. }
  72. return await r;
  73. } finally {
  74. asyncHandlers.delete(onLeave);
  75. }
  76. }
  77. };
  78. }
  79. function createNamespace(defaultOpts = {}) {
  80. const contexts = {};
  81. return {
  82. get(key, opts = {}) {
  83. if (!contexts[key]) {
  84. contexts[key] = createContext({ ...defaultOpts, ...opts });
  85. }
  86. return contexts[key];
  87. }
  88. };
  89. }
  90. const _globalThis = typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : typeof window !== "undefined" ? window : {};
  91. const globalKey = "__unctx__";
  92. const defaultNamespace = _globalThis[globalKey] || (_globalThis[globalKey] = createNamespace());
  93. const getContext = (key, opts = {}) => defaultNamespace.get(key, opts);
  94. const useContext = (key, opts = {}) => getContext(key, opts).use;
  95. const asyncHandlersKey = "__unctx_async_handlers__";
  96. const asyncHandlers = _globalThis[asyncHandlersKey] || (_globalThis[asyncHandlersKey] = /* @__PURE__ */ new Set());
  97. function executeAsync(function_) {
  98. const restores = [];
  99. for (const leaveHandler of asyncHandlers) {
  100. const restore2 = leaveHandler();
  101. if (restore2) {
  102. restores.push(restore2);
  103. }
  104. }
  105. const restore = () => {
  106. for (const restore2 of restores) {
  107. restore2();
  108. }
  109. };
  110. let awaitable = function_();
  111. if (awaitable && typeof awaitable === "object" && "catch" in awaitable) {
  112. awaitable = awaitable.catch((error) => {
  113. restore();
  114. throw error;
  115. });
  116. }
  117. return [awaitable, restore];
  118. }
  119. function withAsyncContext(function_, transformed) {
  120. if (!transformed) {
  121. console.warn(
  122. "[unctx] `withAsyncContext` needs transformation for async context support in",
  123. function_,
  124. "\n",
  125. function_.toString()
  126. );
  127. }
  128. return function_;
  129. }
  130. export { createContext, createNamespace, defaultNamespace, executeAsync, getContext, useContext, withAsyncContext };