@athosjs/pro 0.1.4-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +518 -0
  2. package/bootstrap.cjs +107 -0
  3. package/bootstrap.cjs.map +1 -0
  4. package/bootstrap.d.ts +8 -0
  5. package/bootstrap.d.ts.map +1 -0
  6. package/bootstrap.js +103 -0
  7. package/bootstrap.js.map +1 -0
  8. package/core/athos-application.cjs +362 -0
  9. package/core/athos-application.cjs.map +1 -0
  10. package/core/athos-application.d.ts +17 -0
  11. package/core/athos-application.d.ts.map +1 -0
  12. package/core/athos-application.js +357 -0
  13. package/core/athos-application.js.map +1 -0
  14. package/core/discovery.cjs +47 -0
  15. package/core/discovery.cjs.map +1 -0
  16. package/core/discovery.d.ts +6 -0
  17. package/core/discovery.d.ts.map +1 -0
  18. package/core/discovery.js +45 -0
  19. package/core/discovery.js.map +1 -0
  20. package/core/i18n.cjs +12 -0
  21. package/core/i18n.cjs.map +1 -0
  22. package/core/i18n.d.ts +4 -0
  23. package/core/i18n.d.ts.map +1 -0
  24. package/core/i18n.js +10 -0
  25. package/core/i18n.js.map +1 -0
  26. package/core/pipeline.cjs +251 -0
  27. package/core/pipeline.cjs.map +1 -0
  28. package/core/pipeline.d.ts +11 -0
  29. package/core/pipeline.d.ts.map +1 -0
  30. package/core/pipeline.js +246 -0
  31. package/core/pipeline.js.map +1 -0
  32. package/core/router-initializer.cjs +158 -0
  33. package/core/router-initializer.cjs.map +1 -0
  34. package/core/router-initializer.d.ts +26 -0
  35. package/core/router-initializer.d.ts.map +1 -0
  36. package/core/router-initializer.js +156 -0
  37. package/core/router-initializer.js.map +1 -0
  38. package/core/scanner.cjs +141 -0
  39. package/core/scanner.cjs.map +1 -0
  40. package/core/scanner.d.ts +7 -0
  41. package/core/scanner.d.ts.map +1 -0
  42. package/core/scanner.js +139 -0
  43. package/core/scanner.js.map +1 -0
  44. package/experimental.cjs +23 -0
  45. package/experimental.cjs.map +1 -0
  46. package/experimental.d.ts +9 -0
  47. package/experimental.d.ts.map +1 -0
  48. package/experimental.js +5 -0
  49. package/experimental.js.map +1 -0
  50. package/functions.cjs +67 -0
  51. package/functions.cjs.map +1 -0
  52. package/functions.d.ts +10 -0
  53. package/functions.d.ts.map +1 -0
  54. package/functions.js +62 -0
  55. package/functions.js.map +1 -0
  56. package/http-profile.cjs +48 -0
  57. package/http-profile.cjs.map +1 -0
  58. package/http-profile.d.ts +6 -0
  59. package/http-profile.d.ts.map +1 -0
  60. package/http-profile.js +44 -0
  61. package/http-profile.js.map +1 -0
  62. package/index.cjs +281 -0
  63. package/index.cjs.map +1 -0
  64. package/index.d.ts +23 -0
  65. package/index.d.ts.map +1 -0
  66. package/index.js +23 -0
  67. package/index.js.map +1 -0
  68. package/observability.cjs +191 -0
  69. package/observability.cjs.map +1 -0
  70. package/observability.d.ts +8 -0
  71. package/observability.d.ts.map +1 -0
  72. package/observability.js +188 -0
  73. package/observability.js.map +1 -0
  74. package/package.json +42 -0
  75. package/policies.cjs +30 -0
  76. package/policies.cjs.map +1 -0
  77. package/policies.d.ts +21 -0
  78. package/policies.d.ts.map +1 -0
  79. package/policies.js +27 -0
  80. package/policies.js.map +1 -0
  81. package/resilience.cjs +280 -0
  82. package/resilience.cjs.map +1 -0
  83. package/resilience.d.ts +6 -0
  84. package/resilience.d.ts.map +1 -0
  85. package/resilience.js +276 -0
  86. package/resilience.js.map +1 -0
  87. package/security.cjs +142 -0
  88. package/security.cjs.map +1 -0
  89. package/security.d.ts +11 -0
  90. package/security.d.ts.map +1 -0
  91. package/security.js +136 -0
  92. package/security.js.map +1 -0
  93. package/types.d.ts +3 -0
  94. package/types.d.ts.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience.cjs","sources":["../../../packages/pro/src/resilience.ts"],"sourcesContent":["import { ATHOS_ERROR_CODES } from \"@athosjs/constants\";\nimport { createAthosError } from \"@athosjs/core\";\nimport type {\n\tCircuitBreaker,\n\tCircuitBreakerOptions,\n\tCircuitBreakerState,\n\tConcurrencyLimiter,\n\tConcurrencyLimiterOptions,\n\tResilientExecutor,\n\tResilientExecutorOptions,\n} from \"@athosjs/types/pro\";\n\nexport type {\n\tCircuitBreaker,\n\tCircuitBreakerOptions,\n\tCircuitBreakerState,\n\tConcurrencyLimiter,\n\tConcurrencyLimiterOptions,\n\tResilientExecutor,\n\tResilientExecutorOptions,\n};\n\ninterface QueueEntry<T> {\n\treadonly operation: (signal?: AbortSignal) => Promise<T> | T;\n\treadonly signal?: AbortSignal | undefined;\n\treadonly resolve: (value: T | PromiseLike<T>) => void;\n\treadonly reject: (reason?: unknown) => void;\n\tabortHandler?: (() => void) | undefined;\n}\n\nexport function createConcurrencyLimiter(options: ConcurrencyLimiterOptions): ConcurrencyLimiter {\n\tif (options.maxConcurrency < 1) {\n\t\tthrow createAthosError(\n\t\t\tATHOS_ERROR_CODES.OPERATION_OVERLOADED,\n\t\t\t\"Concurrency limiter requires maxConcurrency to be greater than zero.\",\n\t\t);\n\t}\n\n\tconst queue: QueueEntry<any>[] = [];\n\tlet queueOffset = 0;\n\tlet activeCount = 0;\n\tlet pendingCount = 0;\n\n\tconst pump = (): void => {\n\t\twhile (activeCount < options.maxConcurrency && pendingCount > 0) {\n\t\t\tconst next = queue[queueOffset];\n\t\t\tqueue[queueOffset] = undefined as any;\n\t\t\tqueueOffset++;\n\n\t\t\tif (!next) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tpendingCount -= 1;\n\n\t\t\tif (queueOffset > 1000) {\n\t\t\t\tqueue.splice(0, queueOffset);\n\t\t\t\tqueueOffset = 0;\n\t\t\t}\n\n\t\t\trunEntry(next);\n\t\t}\n\t};\n\n\tconst runEntry = (entry: QueueEntry<any>): void => {\n\t\tif (entry.signal && entry.abortHandler) {\n\t\t\tentry.signal.removeEventListener(\"abort\", entry.abortHandler);\n\t\t\tentry.abortHandler = undefined;\n\t\t}\n\n\t\tif (entry.signal?.aborted) {\n\t\t\tentry.reject(createOverloadedAbortError(\"Queued operation was aborted before execution.\"));\n\t\t\tpump();\n\t\t\treturn;\n\t\t}\n\n\t\tactiveCount += 1;\n\n\t\tconst result = entry.operation(entry.signal);\n\t\tif (result instanceof Promise) {\n\t\t\tresult.then(entry.resolve, entry.reject).finally(() => {\n\t\t\t\tactiveCount -= 1;\n\t\t\t\tpump();\n\t\t\t});\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tentry.resolve(result);\n\t\t\t} catch (e) {\n\t\t\t\tentry.reject(e);\n\t\t\t} finally {\n\t\t\t\tactiveCount -= 1;\n\t\t\t\tpump();\n\t\t\t}\n\t\t}\n\t};\n\n\treturn {\n\t\tget activeCount(): number {\n\t\t\treturn activeCount;\n\t\t},\n\t\tget pendingCount(): number {\n\t\t\treturn pendingCount;\n\t\t},\n\t\trun<T>(operation: (signal?: AbortSignal) => Promise<T> | T, runOptions: { signal?: AbortSignal } = {}): Promise<T> {\n\t\t\tif (runOptions.signal?.aborted) {\n\t\t\t\treturn Promise.reject(createOverloadedAbortError(\"Operation was aborted before entering the limiter.\"));\n\t\t\t}\n\n\t\t\tif (activeCount < options.maxConcurrency) {\n\t\t\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\t\t\trunEntry({\n\t\t\t\t\t\toperation,\n\t\t\t\t\t\tsignal: runOptions.signal,\n\t\t\t\t\t\tresolve,\n\t\t\t\t\t\treject,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst maxQueueSize = options.maxQueueSize ?? Number.POSITIVE_INFINITY;\n\n\t\t\tif (pendingCount >= maxQueueSize) {\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tcreateAthosError(ATHOS_ERROR_CODES.OPERATION_OVERLOADED, \"Concurrency limiter queue is full.\", {\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\tactiveCount,\n\t\t\t\t\t\t\tpendingCount,\n\t\t\t\t\t\t\tmaxConcurrency: options.maxConcurrency,\n\t\t\t\t\t\t\tmaxQueueSize,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\t\tconst entry: QueueEntry<T> = {\n\t\t\t\t\toperation,\n\t\t\t\t\tsignal: runOptions.signal,\n\t\t\t\t\tresolve,\n\t\t\t\t\treject,\n\t\t\t\t};\n\n\t\t\t\tif (runOptions.signal) {\n\t\t\t\t\tconst onAbort = (): void => {\n\t\t\t\t\t\tconst idx = queue.indexOf(entry as any, queueOffset);\n\t\t\t\t\t\tif (idx !== -1) {\n\t\t\t\t\t\t\tqueue[idx] = undefined as any;\n\t\t\t\t\t\t\tpendingCount -= 1;\n\t\t\t\t\t\t\trunOptions.signal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tentry.abortHandler = undefined;\n\t\t\t\t\t\t\treject(createOverloadedAbortError(\"Queued operation was aborted.\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tentry.abortHandler = onAbort;\n\t\t\t\t\trunOptions.signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\n\t\t\t\tqueue.push(entry as QueueEntry<any>);\n\t\t\t\tpendingCount += 1;\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport function createCircuitBreaker(options: CircuitBreakerOptions): CircuitBreaker {\n\tif (options.failureThreshold < 1) {\n\t\tthrow createAthosError(\n\t\t\tATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN,\n\t\t\t\"Circuit breaker requires failureThreshold to be greater than zero.\",\n\t\t);\n\t}\n\n\tlet state: CircuitBreakerState = \"closed\";\n\tlet failureCount = 0;\n\tlet openedAt: number | undefined;\n\tlet halfOpenAttempts = 0;\n\n\tconst moveToOpen = (): void => {\n\t\tstate = \"open\";\n\t\topenedAt = Date.now();\n\t\thalfOpenAttempts = 0;\n\t};\n\n\tconst moveToClosed = (): void => {\n\t\tstate = \"closed\";\n\t\tfailureCount = 0;\n\t\topenedAt = undefined;\n\t\thalfOpenAttempts = 0;\n\t};\n\n\tconst moveToHalfOpenIfReady = (): void => {\n\t\tif (state === \"open\" && openedAt !== undefined && Date.now() - openedAt >= options.resetAfterMs) {\n\t\t\tstate = \"half-open\";\n\t\t\thalfOpenAttempts = 0;\n\t\t}\n\t};\n\n\treturn {\n\t\tget state(): CircuitBreakerState {\n\t\t\tmoveToHalfOpenIfReady();\n\t\t\treturn state;\n\t\t},\n\t\tget failureCount(): number {\n\t\t\treturn failureCount;\n\t\t},\n\t\tget openedAt(): number | undefined {\n\t\t\treturn openedAt;\n\t\t},\n\t\tasync execute<T>(\n\t\t\toperation: (signal?: AbortSignal) => Promise<T> | T,\n\t\t\trunOptions: { signal?: AbortSignal } = {},\n\t\t): Promise<T> {\n\t\t\tmoveToHalfOpenIfReady();\n\n\t\t\tif (state === \"open\") {\n\t\t\t\tthrow createAthosError(ATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN, \"Circuit breaker is open.\", {\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\topenedAt,\n\t\t\t\t\t\tresetAfterMs: options.resetAfterMs,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (state === \"half-open\") {\n\t\t\t\tconst allowedAttempts = options.halfOpenMaxAttempts ?? 1;\n\n\t\t\t\tif (halfOpenAttempts >= allowedAttempts) {\n\t\t\t\t\tthrow createAthosError(\n\t\t\t\t\t\tATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN,\n\t\t\t\t\t\t\"Circuit breaker half-open probe limit reached.\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\topenedAt,\n\t\t\t\t\t\t\t\tallowedAttempts,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\thalfOpenAttempts += 1;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await operation(runOptions.signal);\n\t\t\t\tmoveToClosed();\n\t\t\t\treturn result;\n\t\t\t} catch (error) {\n\t\t\t\tfailureCount += 1;\n\n\t\t\t\tif (state === \"half-open\" || failureCount >= options.failureThreshold) {\n\t\t\t\t\tmoveToOpen();\n\t\t\t\t}\n\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function createResilientExecutor(options: ResilientExecutorOptions = {}): ResilientExecutor {\n\treturn {\n\t\tasync execute<T>(\n\t\t\toperation: (signal?: AbortSignal) => Promise<T> | T,\n\t\t\trunOptions: { signal?: AbortSignal } = {},\n\t\t): Promise<T> {\n\t\t\tconst attempt = (signal?: AbortSignal): Promise<T> => {\n\t\t\t\tconst result = options.timeoutMs\n\t\t\t\t\t? withTimeout((timeoutSignal) => operation(timeoutSignal), options.timeoutMs, signal)\n\t\t\t\t\t: operation(signal);\n\n\t\t\t\treturn result instanceof Promise ? result : Promise.resolve(result);\n\t\t\t};\n\n\t\t\tconst executeWithBreaker = (signal?: AbortSignal): Promise<T> => {\n\t\t\t\tif (options.circuitBreaker) {\n\t\t\t\t\treturn options.circuitBreaker.execute((breakerSignal) => attempt(breakerSignal), {\n\t\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn attempt(signal);\n\t\t\t};\n\n\t\t\tif (options.limiter) {\n\t\t\t\treturn options.limiter.run((limiterSignal) => executeWithBreaker(limiterSignal), runOptions);\n\t\t\t}\n\n\t\t\treturn executeWithBreaker(runOptions.signal);\n\t\t},\n\t};\n}\n\nfunction withTimeout<T>(\n\toperation: (signal?: AbortSignal) => Promise<T> | T,\n\ttimeoutMs: number,\n\tupstreamSignal?: AbortSignal,\n): Promise<T> {\n\tif (timeoutMs <= 0) {\n\t\treturn Promise.reject(\n\t\t\tcreateAthosError(ATHOS_ERROR_CODES.OPERATION_TIMEOUT, \"Operation timeout must be greater than zero.\"),\n\t\t);\n\t}\n\n\tif (upstreamSignal?.aborted) {\n\t\treturn Promise.reject(upstreamSignal.reason || new Error(\"Aborted\"));\n\t}\n\n\tconst controller = new AbortController();\n\tconst detach = upstreamSignal ? forwardAbort(upstreamSignal, controller) : undefined;\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst timeout = setTimeout(() => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcontroller.abort();\n\t\t\treject(createAthosError(ATHOS_ERROR_CODES.OPERATION_TIMEOUT, \"Operation timed out.\", { details: { timeoutMs } }));\n\t\t}, timeoutMs);\n\n\t\tconst cleanup = (err?: any) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeout);\n\t\t\tif (detach) detach();\n\t\t\tif (err) reject(err);\n\t\t};\n\n\t\ttry {\n\t\t\tconst res = operation(controller.signal);\n\t\t\tif (res instanceof Promise) {\n\t\t\t\tres.then((val) => {\n\t\t\t\t\tcleanup();\n\t\t\t\t\tresolve(val);\n\t\t\t\t}, cleanup);\n\t\t\t} else {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(res);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tcleanup(e);\n\t\t}\n\t});\n}\n\nfunction forwardAbort(signal: AbortSignal | undefined, controller: AbortController): () => void {\n\tif (!signal) {\n\t\treturn () => undefined;\n\t}\n\n\tif (signal.aborted) {\n\t\tcontroller.abort();\n\t\treturn () => undefined;\n\t}\n\n\tconst onAbort = (): void => controller.abort();\n\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\treturn () => signal.removeEventListener(\"abort\", onAbort);\n}\n\nfunction createOverloadedAbortError(message: string) {\n\treturn createAthosError(ATHOS_ERROR_CODES.OPERATION_OVERLOADED, message);\n}\n"],"names":["createConcurrencyLimiter","options","maxConcurrency","createAthosError","ATHOS_ERROR_CODES","OPERATION_OVERLOADED","queue","queueOffset","activeCount","pendingCount","pump","next","undefined","splice","runEntry","entry","signal","abortHandler","removeEventListener","aborted","reject","createOverloadedAbortError","result","operation","Promise","then","resolve","finally","e","run","runOptions","maxQueueSize","Number","POSITIVE_INFINITY","details","onAbort","idx","indexOf","addEventListener","once","push","createCircuitBreaker","failureThreshold","OPERATION_CIRCUIT_OPEN","state","failureCount","openedAt","halfOpenAttempts","moveToOpen","Date","now","moveToClosed","moveToHalfOpenIfReady","resetAfterMs","execute","allowedAttempts","halfOpenMaxAttempts","error","createResilientExecutor","attempt","timeoutMs","withTimeout","timeoutSignal","executeWithBreaker","circuitBreaker","breakerSignal","limiter","limiterSignal","upstreamSignal","OPERATION_TIMEOUT","reason","Error","controller","AbortController","detach","forwardAbort","settled","timeout","setTimeout","abort","cleanup","err","clearTimeout","res","val","message"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { CircuitBreaker, CircuitBreakerOptions, CircuitBreakerState, ConcurrencyLimiter, ConcurrencyLimiterOptions, ResilientExecutor, ResilientExecutorOptions } from "@athosjs/types/pro";
2
+ export type { CircuitBreaker, CircuitBreakerOptions, CircuitBreakerState, ConcurrencyLimiter, ConcurrencyLimiterOptions, ResilientExecutor, ResilientExecutorOptions, };
3
+ export declare function createConcurrencyLimiter(options: ConcurrencyLimiterOptions): ConcurrencyLimiter;
4
+ export declare function createCircuitBreaker(options: CircuitBreakerOptions): CircuitBreaker;
5
+ export declare function createResilientExecutor(options?: ResilientExecutorOptions): ResilientExecutor;
6
+ //# sourceMappingURL=resilience.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience.d.ts","sourceRoot":"","sources":["../../../../../../packages/pro/src/resilience.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,wBAAwB,EACxB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACX,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,yBAAyB,EACzB,iBAAiB,EACjB,wBAAwB,GACxB,CAAC;AAUF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAqI/F;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,cAAc,CA6FnF;AAED,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,wBAA6B,GAAG,iBAAiB,CA+BjG"}
package/resilience.js ADDED
@@ -0,0 +1,276 @@
1
+ import { ATHOS_ERROR_CODES } from '@athosjs/constants';
2
+ import { createAthosError } from '@athosjs/core';
3
+
4
+ function createConcurrencyLimiter(options) {
5
+ if (options.maxConcurrency < 1) {
6
+ throw createAthosError(ATHOS_ERROR_CODES.OPERATION_OVERLOADED, "Concurrency limiter requires maxConcurrency to be greater than zero.");
7
+ }
8
+ const queue = [];
9
+ let queueOffset = 0;
10
+ let activeCount = 0;
11
+ let pendingCount = 0;
12
+ const pump = ()=>{
13
+ while(activeCount < options.maxConcurrency && pendingCount > 0){
14
+ const next = queue[queueOffset];
15
+ queue[queueOffset] = undefined;
16
+ queueOffset++;
17
+ if (!next) {
18
+ continue;
19
+ }
20
+ pendingCount -= 1;
21
+ if (queueOffset > 1000) {
22
+ queue.splice(0, queueOffset);
23
+ queueOffset = 0;
24
+ }
25
+ runEntry(next);
26
+ }
27
+ };
28
+ const runEntry = (entry)=>{
29
+ if (entry.signal && entry.abortHandler) {
30
+ entry.signal.removeEventListener("abort", entry.abortHandler);
31
+ entry.abortHandler = undefined;
32
+ }
33
+ if (entry.signal?.aborted) {
34
+ entry.reject(createOverloadedAbortError("Queued operation was aborted before execution."));
35
+ pump();
36
+ return;
37
+ }
38
+ activeCount += 1;
39
+ const result = entry.operation(entry.signal);
40
+ if (result instanceof Promise) {
41
+ result.then(entry.resolve, entry.reject).finally(()=>{
42
+ activeCount -= 1;
43
+ pump();
44
+ });
45
+ } else {
46
+ try {
47
+ entry.resolve(result);
48
+ } catch (e) {
49
+ entry.reject(e);
50
+ } finally{
51
+ activeCount -= 1;
52
+ pump();
53
+ }
54
+ }
55
+ };
56
+ return {
57
+ get activeCount () {
58
+ return activeCount;
59
+ },
60
+ get pendingCount () {
61
+ return pendingCount;
62
+ },
63
+ run (operation, runOptions = {}) {
64
+ if (runOptions.signal?.aborted) {
65
+ return Promise.reject(createOverloadedAbortError("Operation was aborted before entering the limiter."));
66
+ }
67
+ if (activeCount < options.maxConcurrency) {
68
+ return new Promise((resolve, reject)=>{
69
+ runEntry({
70
+ operation,
71
+ signal: runOptions.signal,
72
+ resolve,
73
+ reject
74
+ });
75
+ });
76
+ }
77
+ const maxQueueSize = options.maxQueueSize ?? Number.POSITIVE_INFINITY;
78
+ if (pendingCount >= maxQueueSize) {
79
+ return Promise.reject(createAthosError(ATHOS_ERROR_CODES.OPERATION_OVERLOADED, "Concurrency limiter queue is full.", {
80
+ details: {
81
+ activeCount,
82
+ pendingCount,
83
+ maxConcurrency: options.maxConcurrency,
84
+ maxQueueSize
85
+ }
86
+ }));
87
+ }
88
+ return new Promise((resolve, reject)=>{
89
+ const entry = {
90
+ operation,
91
+ signal: runOptions.signal,
92
+ resolve,
93
+ reject
94
+ };
95
+ if (runOptions.signal) {
96
+ const onAbort = ()=>{
97
+ const idx = queue.indexOf(entry, queueOffset);
98
+ if (idx !== -1) {
99
+ queue[idx] = undefined;
100
+ pendingCount -= 1;
101
+ runOptions.signal?.removeEventListener("abort", onAbort);
102
+ entry.abortHandler = undefined;
103
+ reject(createOverloadedAbortError("Queued operation was aborted."));
104
+ }
105
+ };
106
+ entry.abortHandler = onAbort;
107
+ runOptions.signal.addEventListener("abort", onAbort, {
108
+ once: true
109
+ });
110
+ }
111
+ queue.push(entry);
112
+ pendingCount += 1;
113
+ });
114
+ }
115
+ };
116
+ }
117
+ function createCircuitBreaker(options) {
118
+ if (options.failureThreshold < 1) {
119
+ throw createAthosError(ATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN, "Circuit breaker requires failureThreshold to be greater than zero.");
120
+ }
121
+ let state = "closed";
122
+ let failureCount = 0;
123
+ let openedAt;
124
+ let halfOpenAttempts = 0;
125
+ const moveToOpen = ()=>{
126
+ state = "open";
127
+ openedAt = Date.now();
128
+ halfOpenAttempts = 0;
129
+ };
130
+ const moveToClosed = ()=>{
131
+ state = "closed";
132
+ failureCount = 0;
133
+ openedAt = undefined;
134
+ halfOpenAttempts = 0;
135
+ };
136
+ const moveToHalfOpenIfReady = ()=>{
137
+ if (state === "open" && openedAt !== undefined && Date.now() - openedAt >= options.resetAfterMs) {
138
+ state = "half-open";
139
+ halfOpenAttempts = 0;
140
+ }
141
+ };
142
+ return {
143
+ get state () {
144
+ moveToHalfOpenIfReady();
145
+ return state;
146
+ },
147
+ get failureCount () {
148
+ return failureCount;
149
+ },
150
+ get openedAt () {
151
+ return openedAt;
152
+ },
153
+ async execute (operation, runOptions = {}) {
154
+ moveToHalfOpenIfReady();
155
+ if (state === "open") {
156
+ throw createAthosError(ATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN, "Circuit breaker is open.", {
157
+ details: {
158
+ openedAt,
159
+ resetAfterMs: options.resetAfterMs
160
+ }
161
+ });
162
+ }
163
+ if (state === "half-open") {
164
+ const allowedAttempts = options.halfOpenMaxAttempts ?? 1;
165
+ if (halfOpenAttempts >= allowedAttempts) {
166
+ throw createAthosError(ATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN, "Circuit breaker half-open probe limit reached.", {
167
+ details: {
168
+ openedAt,
169
+ allowedAttempts
170
+ }
171
+ });
172
+ }
173
+ halfOpenAttempts += 1;
174
+ }
175
+ try {
176
+ const result = await operation(runOptions.signal);
177
+ moveToClosed();
178
+ return result;
179
+ } catch (error) {
180
+ failureCount += 1;
181
+ if (state === "half-open" || failureCount >= options.failureThreshold) {
182
+ moveToOpen();
183
+ }
184
+ throw error;
185
+ }
186
+ }
187
+ };
188
+ }
189
+ function createResilientExecutor(options = {}) {
190
+ return {
191
+ async execute (operation, runOptions = {}) {
192
+ const attempt = (signal)=>{
193
+ const result = options.timeoutMs ? withTimeout((timeoutSignal)=>operation(timeoutSignal), options.timeoutMs, signal) : operation(signal);
194
+ return result instanceof Promise ? result : Promise.resolve(result);
195
+ };
196
+ const executeWithBreaker = (signal)=>{
197
+ if (options.circuitBreaker) {
198
+ return options.circuitBreaker.execute((breakerSignal)=>attempt(breakerSignal), {
199
+ ...signal === undefined ? {} : {
200
+ signal
201
+ }
202
+ });
203
+ }
204
+ return attempt(signal);
205
+ };
206
+ if (options.limiter) {
207
+ return options.limiter.run((limiterSignal)=>executeWithBreaker(limiterSignal), runOptions);
208
+ }
209
+ return executeWithBreaker(runOptions.signal);
210
+ }
211
+ };
212
+ }
213
+ function withTimeout(operation, timeoutMs, upstreamSignal) {
214
+ if (timeoutMs <= 0) {
215
+ return Promise.reject(createAthosError(ATHOS_ERROR_CODES.OPERATION_TIMEOUT, "Operation timeout must be greater than zero."));
216
+ }
217
+ if (upstreamSignal?.aborted) {
218
+ return Promise.reject(upstreamSignal.reason || new Error("Aborted"));
219
+ }
220
+ const controller = new AbortController();
221
+ const detach = upstreamSignal ? forwardAbort(upstreamSignal, controller) : undefined;
222
+ return new Promise((resolve, reject)=>{
223
+ let settled = false;
224
+ const timeout = setTimeout(()=>{
225
+ if (settled) return;
226
+ settled = true;
227
+ controller.abort();
228
+ reject(createAthosError(ATHOS_ERROR_CODES.OPERATION_TIMEOUT, "Operation timed out.", {
229
+ details: {
230
+ timeoutMs
231
+ }
232
+ }));
233
+ }, timeoutMs);
234
+ const cleanup = (err)=>{
235
+ if (settled) return;
236
+ settled = true;
237
+ clearTimeout(timeout);
238
+ if (detach) detach();
239
+ if (err) reject(err);
240
+ };
241
+ try {
242
+ const res = operation(controller.signal);
243
+ if (res instanceof Promise) {
244
+ res.then((val)=>{
245
+ cleanup();
246
+ resolve(val);
247
+ }, cleanup);
248
+ } else {
249
+ cleanup();
250
+ resolve(res);
251
+ }
252
+ } catch (e) {
253
+ cleanup(e);
254
+ }
255
+ });
256
+ }
257
+ function forwardAbort(signal, controller) {
258
+ if (!signal) {
259
+ return ()=>undefined;
260
+ }
261
+ if (signal.aborted) {
262
+ controller.abort();
263
+ return ()=>undefined;
264
+ }
265
+ const onAbort = ()=>controller.abort();
266
+ signal.addEventListener("abort", onAbort, {
267
+ once: true
268
+ });
269
+ return ()=>signal.removeEventListener("abort", onAbort);
270
+ }
271
+ function createOverloadedAbortError(message) {
272
+ return createAthosError(ATHOS_ERROR_CODES.OPERATION_OVERLOADED, message);
273
+ }
274
+
275
+ export { createCircuitBreaker, createConcurrencyLimiter, createResilientExecutor };
276
+ //# sourceMappingURL=resilience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resilience.js","sources":["../../../packages/pro/src/resilience.ts"],"sourcesContent":["import { ATHOS_ERROR_CODES } from \"@athosjs/constants\";\nimport { createAthosError } from \"@athosjs/core\";\nimport type {\n\tCircuitBreaker,\n\tCircuitBreakerOptions,\n\tCircuitBreakerState,\n\tConcurrencyLimiter,\n\tConcurrencyLimiterOptions,\n\tResilientExecutor,\n\tResilientExecutorOptions,\n} from \"@athosjs/types/pro\";\n\nexport type {\n\tCircuitBreaker,\n\tCircuitBreakerOptions,\n\tCircuitBreakerState,\n\tConcurrencyLimiter,\n\tConcurrencyLimiterOptions,\n\tResilientExecutor,\n\tResilientExecutorOptions,\n};\n\ninterface QueueEntry<T> {\n\treadonly operation: (signal?: AbortSignal) => Promise<T> | T;\n\treadonly signal?: AbortSignal | undefined;\n\treadonly resolve: (value: T | PromiseLike<T>) => void;\n\treadonly reject: (reason?: unknown) => void;\n\tabortHandler?: (() => void) | undefined;\n}\n\nexport function createConcurrencyLimiter(options: ConcurrencyLimiterOptions): ConcurrencyLimiter {\n\tif (options.maxConcurrency < 1) {\n\t\tthrow createAthosError(\n\t\t\tATHOS_ERROR_CODES.OPERATION_OVERLOADED,\n\t\t\t\"Concurrency limiter requires maxConcurrency to be greater than zero.\",\n\t\t);\n\t}\n\n\tconst queue: QueueEntry<any>[] = [];\n\tlet queueOffset = 0;\n\tlet activeCount = 0;\n\tlet pendingCount = 0;\n\n\tconst pump = (): void => {\n\t\twhile (activeCount < options.maxConcurrency && pendingCount > 0) {\n\t\t\tconst next = queue[queueOffset];\n\t\t\tqueue[queueOffset] = undefined as any;\n\t\t\tqueueOffset++;\n\n\t\t\tif (!next) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tpendingCount -= 1;\n\n\t\t\tif (queueOffset > 1000) {\n\t\t\t\tqueue.splice(0, queueOffset);\n\t\t\t\tqueueOffset = 0;\n\t\t\t}\n\n\t\t\trunEntry(next);\n\t\t}\n\t};\n\n\tconst runEntry = (entry: QueueEntry<any>): void => {\n\t\tif (entry.signal && entry.abortHandler) {\n\t\t\tentry.signal.removeEventListener(\"abort\", entry.abortHandler);\n\t\t\tentry.abortHandler = undefined;\n\t\t}\n\n\t\tif (entry.signal?.aborted) {\n\t\t\tentry.reject(createOverloadedAbortError(\"Queued operation was aborted before execution.\"));\n\t\t\tpump();\n\t\t\treturn;\n\t\t}\n\n\t\tactiveCount += 1;\n\n\t\tconst result = entry.operation(entry.signal);\n\t\tif (result instanceof Promise) {\n\t\t\tresult.then(entry.resolve, entry.reject).finally(() => {\n\t\t\t\tactiveCount -= 1;\n\t\t\t\tpump();\n\t\t\t});\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tentry.resolve(result);\n\t\t\t} catch (e) {\n\t\t\t\tentry.reject(e);\n\t\t\t} finally {\n\t\t\t\tactiveCount -= 1;\n\t\t\t\tpump();\n\t\t\t}\n\t\t}\n\t};\n\n\treturn {\n\t\tget activeCount(): number {\n\t\t\treturn activeCount;\n\t\t},\n\t\tget pendingCount(): number {\n\t\t\treturn pendingCount;\n\t\t},\n\t\trun<T>(operation: (signal?: AbortSignal) => Promise<T> | T, runOptions: { signal?: AbortSignal } = {}): Promise<T> {\n\t\t\tif (runOptions.signal?.aborted) {\n\t\t\t\treturn Promise.reject(createOverloadedAbortError(\"Operation was aborted before entering the limiter.\"));\n\t\t\t}\n\n\t\t\tif (activeCount < options.maxConcurrency) {\n\t\t\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\t\t\trunEntry({\n\t\t\t\t\t\toperation,\n\t\t\t\t\t\tsignal: runOptions.signal,\n\t\t\t\t\t\tresolve,\n\t\t\t\t\t\treject,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst maxQueueSize = options.maxQueueSize ?? Number.POSITIVE_INFINITY;\n\n\t\t\tif (pendingCount >= maxQueueSize) {\n\t\t\t\treturn Promise.reject(\n\t\t\t\t\tcreateAthosError(ATHOS_ERROR_CODES.OPERATION_OVERLOADED, \"Concurrency limiter queue is full.\", {\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\tactiveCount,\n\t\t\t\t\t\t\tpendingCount,\n\t\t\t\t\t\t\tmaxConcurrency: options.maxConcurrency,\n\t\t\t\t\t\t\tmaxQueueSize,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\t\tconst entry: QueueEntry<T> = {\n\t\t\t\t\toperation,\n\t\t\t\t\tsignal: runOptions.signal,\n\t\t\t\t\tresolve,\n\t\t\t\t\treject,\n\t\t\t\t};\n\n\t\t\t\tif (runOptions.signal) {\n\t\t\t\t\tconst onAbort = (): void => {\n\t\t\t\t\t\tconst idx = queue.indexOf(entry as any, queueOffset);\n\t\t\t\t\t\tif (idx !== -1) {\n\t\t\t\t\t\t\tqueue[idx] = undefined as any;\n\t\t\t\t\t\t\tpendingCount -= 1;\n\t\t\t\t\t\t\trunOptions.signal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t\tentry.abortHandler = undefined;\n\t\t\t\t\t\t\treject(createOverloadedAbortError(\"Queued operation was aborted.\"));\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tentry.abortHandler = onAbort;\n\t\t\t\t\trunOptions.signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t}\n\n\t\t\t\tqueue.push(entry as QueueEntry<any>);\n\t\t\t\tpendingCount += 1;\n\t\t\t});\n\t\t},\n\t};\n}\n\nexport function createCircuitBreaker(options: CircuitBreakerOptions): CircuitBreaker {\n\tif (options.failureThreshold < 1) {\n\t\tthrow createAthosError(\n\t\t\tATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN,\n\t\t\t\"Circuit breaker requires failureThreshold to be greater than zero.\",\n\t\t);\n\t}\n\n\tlet state: CircuitBreakerState = \"closed\";\n\tlet failureCount = 0;\n\tlet openedAt: number | undefined;\n\tlet halfOpenAttempts = 0;\n\n\tconst moveToOpen = (): void => {\n\t\tstate = \"open\";\n\t\topenedAt = Date.now();\n\t\thalfOpenAttempts = 0;\n\t};\n\n\tconst moveToClosed = (): void => {\n\t\tstate = \"closed\";\n\t\tfailureCount = 0;\n\t\topenedAt = undefined;\n\t\thalfOpenAttempts = 0;\n\t};\n\n\tconst moveToHalfOpenIfReady = (): void => {\n\t\tif (state === \"open\" && openedAt !== undefined && Date.now() - openedAt >= options.resetAfterMs) {\n\t\t\tstate = \"half-open\";\n\t\t\thalfOpenAttempts = 0;\n\t\t}\n\t};\n\n\treturn {\n\t\tget state(): CircuitBreakerState {\n\t\t\tmoveToHalfOpenIfReady();\n\t\t\treturn state;\n\t\t},\n\t\tget failureCount(): number {\n\t\t\treturn failureCount;\n\t\t},\n\t\tget openedAt(): number | undefined {\n\t\t\treturn openedAt;\n\t\t},\n\t\tasync execute<T>(\n\t\t\toperation: (signal?: AbortSignal) => Promise<T> | T,\n\t\t\trunOptions: { signal?: AbortSignal } = {},\n\t\t): Promise<T> {\n\t\t\tmoveToHalfOpenIfReady();\n\n\t\t\tif (state === \"open\") {\n\t\t\t\tthrow createAthosError(ATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN, \"Circuit breaker is open.\", {\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\topenedAt,\n\t\t\t\t\t\tresetAfterMs: options.resetAfterMs,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (state === \"half-open\") {\n\t\t\t\tconst allowedAttempts = options.halfOpenMaxAttempts ?? 1;\n\n\t\t\t\tif (halfOpenAttempts >= allowedAttempts) {\n\t\t\t\t\tthrow createAthosError(\n\t\t\t\t\t\tATHOS_ERROR_CODES.OPERATION_CIRCUIT_OPEN,\n\t\t\t\t\t\t\"Circuit breaker half-open probe limit reached.\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\t\topenedAt,\n\t\t\t\t\t\t\t\tallowedAttempts,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\thalfOpenAttempts += 1;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await operation(runOptions.signal);\n\t\t\t\tmoveToClosed();\n\t\t\t\treturn result;\n\t\t\t} catch (error) {\n\t\t\t\tfailureCount += 1;\n\n\t\t\t\tif (state === \"half-open\" || failureCount >= options.failureThreshold) {\n\t\t\t\t\tmoveToOpen();\n\t\t\t\t}\n\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function createResilientExecutor(options: ResilientExecutorOptions = {}): ResilientExecutor {\n\treturn {\n\t\tasync execute<T>(\n\t\t\toperation: (signal?: AbortSignal) => Promise<T> | T,\n\t\t\trunOptions: { signal?: AbortSignal } = {},\n\t\t): Promise<T> {\n\t\t\tconst attempt = (signal?: AbortSignal): Promise<T> => {\n\t\t\t\tconst result = options.timeoutMs\n\t\t\t\t\t? withTimeout((timeoutSignal) => operation(timeoutSignal), options.timeoutMs, signal)\n\t\t\t\t\t: operation(signal);\n\n\t\t\t\treturn result instanceof Promise ? result : Promise.resolve(result);\n\t\t\t};\n\n\t\t\tconst executeWithBreaker = (signal?: AbortSignal): Promise<T> => {\n\t\t\t\tif (options.circuitBreaker) {\n\t\t\t\t\treturn options.circuitBreaker.execute((breakerSignal) => attempt(breakerSignal), {\n\t\t\t\t\t\t...(signal === undefined ? {} : { signal }),\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\treturn attempt(signal);\n\t\t\t};\n\n\t\t\tif (options.limiter) {\n\t\t\t\treturn options.limiter.run((limiterSignal) => executeWithBreaker(limiterSignal), runOptions);\n\t\t\t}\n\n\t\t\treturn executeWithBreaker(runOptions.signal);\n\t\t},\n\t};\n}\n\nfunction withTimeout<T>(\n\toperation: (signal?: AbortSignal) => Promise<T> | T,\n\ttimeoutMs: number,\n\tupstreamSignal?: AbortSignal,\n): Promise<T> {\n\tif (timeoutMs <= 0) {\n\t\treturn Promise.reject(\n\t\t\tcreateAthosError(ATHOS_ERROR_CODES.OPERATION_TIMEOUT, \"Operation timeout must be greater than zero.\"),\n\t\t);\n\t}\n\n\tif (upstreamSignal?.aborted) {\n\t\treturn Promise.reject(upstreamSignal.reason || new Error(\"Aborted\"));\n\t}\n\n\tconst controller = new AbortController();\n\tconst detach = upstreamSignal ? forwardAbort(upstreamSignal, controller) : undefined;\n\n\treturn new Promise<T>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tconst timeout = setTimeout(() => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcontroller.abort();\n\t\t\treject(createAthosError(ATHOS_ERROR_CODES.OPERATION_TIMEOUT, \"Operation timed out.\", { details: { timeoutMs } }));\n\t\t}, timeoutMs);\n\n\t\tconst cleanup = (err?: any) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeout);\n\t\t\tif (detach) detach();\n\t\t\tif (err) reject(err);\n\t\t};\n\n\t\ttry {\n\t\t\tconst res = operation(controller.signal);\n\t\t\tif (res instanceof Promise) {\n\t\t\t\tres.then((val) => {\n\t\t\t\t\tcleanup();\n\t\t\t\t\tresolve(val);\n\t\t\t\t}, cleanup);\n\t\t\t} else {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(res);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tcleanup(e);\n\t\t}\n\t});\n}\n\nfunction forwardAbort(signal: AbortSignal | undefined, controller: AbortController): () => void {\n\tif (!signal) {\n\t\treturn () => undefined;\n\t}\n\n\tif (signal.aborted) {\n\t\tcontroller.abort();\n\t\treturn () => undefined;\n\t}\n\n\tconst onAbort = (): void => controller.abort();\n\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\treturn () => signal.removeEventListener(\"abort\", onAbort);\n}\n\nfunction createOverloadedAbortError(message: string) {\n\treturn createAthosError(ATHOS_ERROR_CODES.OPERATION_OVERLOADED, message);\n}\n"],"names":["createConcurrencyLimiter","options","maxConcurrency","createAthosError","ATHOS_ERROR_CODES","OPERATION_OVERLOADED","queue","queueOffset","activeCount","pendingCount","pump","next","undefined","splice","runEntry","entry","signal","abortHandler","removeEventListener","aborted","reject","createOverloadedAbortError","result","operation","Promise","then","resolve","finally","e","run","runOptions","maxQueueSize","Number","POSITIVE_INFINITY","details","onAbort","idx","indexOf","addEventListener","once","push","createCircuitBreaker","failureThreshold","OPERATION_CIRCUIT_OPEN","state","failureCount","openedAt","halfOpenAttempts","moveToOpen","Date","now","moveToClosed","moveToHalfOpenIfReady","resetAfterMs","execute","allowedAttempts","halfOpenMaxAttempts","error","createResilientExecutor","attempt","timeoutMs","withTimeout","timeoutSignal","executeWithBreaker","circuitBreaker","breakerSignal","limiter","limiterSignal","upstreamSignal","OPERATION_TIMEOUT","reason","Error","controller","AbortController","detach","forwardAbort","settled","timeout","setTimeout","abort","cleanup","err","clearTimeout","res","val","message"],"mappings":"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"}
package/security.cjs ADDED
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ var auth = require('@athosjs/auth');
4
+ var constants = require('@athosjs/constants');
5
+ var core = require('@athosjs/core');
6
+ var http = require('@athosjs/http');
7
+
8
+ function createProAuthenticationMiddleware(options) {
9
+ return async (context, next)=>{
10
+ const typedContext = context;
11
+ const existing = auth.getAuthentication(typedContext);
12
+ if (options.skipIfAuthenticated !== false && existing?.authenticated) {
13
+ return next();
14
+ }
15
+ const strategies = typeof options.strategies === "function" ? options.strategies(typedContext) : options.strategies;
16
+ const result = await auth.authenticate(typedContext, strategies, {
17
+ ...options.stopOnFailure === undefined ? {} : {
18
+ stopOnFailure: options.stopOnFailure
19
+ }
20
+ });
21
+ auth.attachAuthentication(typedContext, result);
22
+ if (result.authenticated || !options.required) {
23
+ return next();
24
+ }
25
+ if (options.onUnauthenticated) {
26
+ return options.onUnauthenticated(typedContext, result);
27
+ }
28
+ return createAuthenticationFailureResponse(result);
29
+ };
30
+ }
31
+ function createProAuthorizationMiddleware(options) {
32
+ return async (context, next)=>{
33
+ const typedContext = context;
34
+ const authState = auth.getAuthentication(typedContext);
35
+ let subject;
36
+ try {
37
+ subject = options.getSubject ? options.getSubject(typedContext) : auth.authenticatedSubject(authState ?? {
38
+ authenticated: false,
39
+ identity: undefined,
40
+ attempts: [],
41
+ challenges: []
42
+ });
43
+ } catch (error) {
44
+ if (error instanceof core.AthosError && error.code === constants.ATHOS_ERROR_CODES.AUTH_UNAUTHENTICATED) {
45
+ typedContext.state.set(auth.AUTH_STATE_KEY, authState);
46
+ if (options.onUnauthenticated) {
47
+ return options.onUnauthenticated(typedContext, error);
48
+ }
49
+ return createAuthenticationFailureResponse({
50
+ attempts: authState?.attempts ?? [],
51
+ challenges: authState?.challenges ?? [],
52
+ ...authState?.failure ? {
53
+ failure: authState.failure
54
+ } : {}
55
+ });
56
+ }
57
+ throw error;
58
+ }
59
+ const decisionInput = {
60
+ subject,
61
+ ...options.getResource ? {
62
+ resource: options.getResource(typedContext)
63
+ } : {},
64
+ ...options.getEnvironment ? {
65
+ context: options.getEnvironment(typedContext)
66
+ } : {}
67
+ };
68
+ const decision = await auth.authorize(options.policy, decisionInput);
69
+ typedContext.state.set(constants.ATHOS_STATE_KEYS.AUTHZ, decision);
70
+ if (decision.allowed) {
71
+ return next();
72
+ }
73
+ if (options.onForbidden) {
74
+ return options.onForbidden(typedContext, decision);
75
+ }
76
+ return createAuthorizationFailureResponse(decision);
77
+ };
78
+ }
79
+ function createAuthenticationFailureResponse(result) {
80
+ const response = http.json({
81
+ error: "unauthorized",
82
+ authenticated: false,
83
+ ...result.failure ? {
84
+ failure: {
85
+ strategy: result.failure.strategy,
86
+ reason: result.failure.reason,
87
+ reasonCode: result.failure.reasonCode
88
+ }
89
+ } : {},
90
+ challenges: result.challenges
91
+ }, 401);
92
+ const headerValue = formatWwwAuthenticateHeader(result.challenges ?? []);
93
+ if (headerValue) {
94
+ response.headers.set?.("www-authenticate", headerValue);
95
+ }
96
+ return response;
97
+ }
98
+ function createAuthorizationFailureResponse(decision) {
99
+ return http.json({
100
+ error: "forbidden",
101
+ allowed: false,
102
+ ...decision.policy ? {
103
+ policy: decision.policy
104
+ } : {},
105
+ ...decision.code ? {
106
+ code: decision.code
107
+ } : {},
108
+ ...decision.reason ? {
109
+ reason: decision.reason
110
+ } : {}
111
+ }, 403);
112
+ }
113
+ function formatWwwAuthenticateHeader(challenges) {
114
+ if (challenges.length === 0) {
115
+ return undefined;
116
+ }
117
+ return challenges.map(formatChallengeInstruction).join(", ");
118
+ }
119
+ function formatChallengeInstruction(challenge) {
120
+ const parts = [
121
+ challenge.scheme
122
+ ];
123
+ if (challenge.realm) {
124
+ parts.push(`realm="${escapeHeaderValue(challenge.realm)}"`);
125
+ }
126
+ if (challenge.params) {
127
+ for (const [key, value] of Object.entries(challenge.params)){
128
+ parts.push(`${key}="${escapeHeaderValue(value)}"`);
129
+ }
130
+ }
131
+ return parts.join(" ");
132
+ }
133
+ function escapeHeaderValue(value) {
134
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
135
+ }
136
+
137
+ exports.createAuthenticationFailureResponse = createAuthenticationFailureResponse;
138
+ exports.createAuthorizationFailureResponse = createAuthorizationFailureResponse;
139
+ exports.createProAuthenticationMiddleware = createProAuthenticationMiddleware;
140
+ exports.createProAuthorizationMiddleware = createProAuthorizationMiddleware;
141
+ exports.formatWwwAuthenticateHeader = formatWwwAuthenticateHeader;
142
+ //# sourceMappingURL=security.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.cjs","sources":["../../../packages/pro/src/security.ts"],"sourcesContent":["import {\n\tAUTH_STATE_KEY,\n\ttype AuthenticationResult,\n\ttype AuthIdentity,\n\ttype AuthStateCarrier,\n\ttype AuthStrategy,\n\tattachAuthentication,\n\tauthenticate,\n\tauthenticatedSubject,\n\tauthorize,\n\ttype ChallengeInstruction,\n\tgetAuthentication,\n} from \"@athosjs/auth\";\nimport type { AuthorizationContext, AuthorizationDecision, AuthorizationPolicy } from \"@athosjs/authz\";\nimport { ATHOS_ERROR_CODES, ATHOS_STATE_KEYS } from \"@athosjs/constants\";\nimport { AthosError } from \"@athosjs/core\";\nimport { type HttpContext, type HttpMiddleware, type HttpResponse, json } from \"@athosjs/http\";\nimport type { ProAuthenticationMiddlewareOptions, ProAuthorizationMiddlewareOptions } from \"@athosjs/types/pro\";\n\nexport type { ProAuthenticationMiddlewareOptions, ProAuthorizationMiddlewareOptions };\n\nexport function createProAuthenticationMiddleware<\n\tTContext extends HttpContext & AuthStateCarrier,\n\tTIdentity extends AuthIdentity = AuthIdentity,\n>(options: ProAuthenticationMiddlewareOptions<TContext, TIdentity>): HttpMiddleware {\n\treturn async (context, next) => {\n\t\tconst typedContext = context as TContext;\n\t\tconst existing = getAuthentication<TIdentity>(typedContext);\n\n\t\tif (options.skipIfAuthenticated !== false && existing?.authenticated) {\n\t\t\treturn next();\n\t\t}\n\n\t\tconst strategies =\n\t\t\ttypeof options.strategies === \"function\"\n\t\t\t\t? (options.strategies as any)(typedContext)\n\t\t\t\t: (options.strategies as readonly AuthStrategy<TContext, TIdentity>[]);\n\t\tconst result = await authenticate(typedContext, strategies as any, {\n\t\t\t...(options.stopOnFailure === undefined ? {} : { stopOnFailure: options.stopOnFailure }),\n\t\t});\n\n\t\tattachAuthentication(typedContext, result);\n\n\t\tif (result.authenticated || !options.required) {\n\t\t\treturn next();\n\t\t}\n\n\t\tif (options.onUnauthenticated) {\n\t\t\treturn (options.onUnauthenticated as any)(typedContext, result) as any;\n\t\t}\n\n\t\treturn createAuthenticationFailureResponse(result);\n\t};\n}\n\nexport function createProAuthorizationMiddleware<\n\tTContext extends HttpContext & AuthStateCarrier,\n\tTIdentity extends AuthIdentity = AuthIdentity,\n\tTResource = unknown,\n\tTEnvironment = unknown,\n>(options: ProAuthorizationMiddlewareOptions<TContext, TIdentity, TResource, TEnvironment>): HttpMiddleware {\n\treturn async (context, next) => {\n\t\tconst typedContext = context as TContext;\n\t\tconst authState = getAuthentication<TIdentity>(typedContext);\n\n\t\tlet subject: TIdentity;\n\n\t\ttry {\n\t\t\tsubject = options.getSubject\n\t\t\t\t? options.getSubject(typedContext)\n\t\t\t\t: authenticatedSubject<TIdentity>((authState ?? {\n\t\t\t\t\t\tauthenticated: false,\n\t\t\t\t\t\tidentity: undefined as any,\n\t\t\t\t\t\tattempts: [],\n\t\t\t\t\t\tchallenges: [],\n\t\t\t\t\t}) as AuthStateCarrier);\n\t\t} catch (error) {\n\t\t\tif (error instanceof AthosError && error.code === ATHOS_ERROR_CODES.AUTH_UNAUTHENTICATED) {\n\t\t\t\ttypedContext.state.set(AUTH_STATE_KEY, authState);\n\n\t\t\t\tif (options.onUnauthenticated) {\n\t\t\t\t\treturn (options.onUnauthenticated as any)(typedContext, error) as any;\n\t\t\t\t}\n\n\t\t\t\treturn createAuthenticationFailureResponse({\n\t\t\t\t\tauthenticated: false,\n\t\t\t\t\tattempts: authState?.attempts ?? [],\n\t\t\t\t\tchallenges: authState?.challenges ?? [],\n\t\t\t\t\t...(authState?.failure ? { failure: authState.failure } : {}),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\n\t\tconst decisionInput: AuthorizationContext<TIdentity, TResource, TEnvironment> = {\n\t\t\tsubject,\n\t\t\t...(options.getResource ? { resource: options.getResource(typedContext) } : {}),\n\t\t\t...(options.getEnvironment ? { context: options.getEnvironment(typedContext) } : {}),\n\t\t};\n\t\tconst decision = await authorize(\n\t\t\toptions.policy as AuthorizationPolicy<TIdentity, TResource, TEnvironment>,\n\t\t\tdecisionInput,\n\t\t);\n\n\t\ttypedContext.state.set(ATHOS_STATE_KEYS.AUTHZ, decision);\n\n\t\tif (decision.allowed) {\n\t\t\treturn next();\n\t\t}\n\n\t\tif (options.onForbidden) {\n\t\t\treturn (options.onForbidden as any)(typedContext, decision) as any;\n\t\t}\n\n\t\treturn createAuthorizationFailureResponse(decision);\n\t};\n}\n\nexport function createAuthenticationFailureResponse<TIdentity extends AuthIdentity = AuthIdentity>(\n\tresult: AuthenticationResult<TIdentity>,\n): HttpResponse {\n\tconst response = json(\n\t\t{\n\t\t\terror: \"unauthorized\",\n\t\t\tauthenticated: false,\n\t\t\t...(result.failure\n\t\t\t\t? {\n\t\t\t\t\t\tfailure: {\n\t\t\t\t\t\t\tstrategy: result.failure.strategy,\n\t\t\t\t\t\t\treason: result.failure.reason,\n\t\t\t\t\t\t\treasonCode: result.failure.reasonCode,\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t\tchallenges: result.challenges,\n\t\t},\n\t\t401,\n\t);\n\tconst headerValue = formatWwwAuthenticateHeader(result.challenges ?? []);\n\n\tif (headerValue) {\n\t\t(response.headers as any).set?.(\"www-authenticate\", headerValue);\n\t}\n\n\treturn response;\n}\n\nexport function createAuthorizationFailureResponse(decision: AuthorizationDecision): HttpResponse {\n\treturn json(\n\t\t{\n\t\t\terror: \"forbidden\",\n\t\t\tallowed: false,\n\t\t\t...(decision.policy ? { policy: decision.policy } : {}),\n\t\t\t...(decision.code ? { code: decision.code } : {}),\n\t\t\t...(decision.reason ? { reason: decision.reason } : {}),\n\t\t},\n\t\t403,\n\t);\n}\n\nexport function formatWwwAuthenticateHeader(challenges: readonly ChallengeInstruction[]): string | undefined {\n\tif (challenges.length === 0) {\n\t\treturn undefined;\n\t}\n\n\treturn challenges.map(formatChallengeInstruction).join(\", \");\n}\n\nfunction formatChallengeInstruction(challenge: ChallengeInstruction): string {\n\tconst parts = [challenge.scheme];\n\n\tif (challenge.realm) {\n\t\tparts.push(`realm=\"${escapeHeaderValue(challenge.realm)}\"`);\n\t}\n\n\tif (challenge.params) {\n\t\tfor (const [key, value] of Object.entries(challenge.params)) {\n\t\t\tparts.push(`${key}=\"${escapeHeaderValue(value)}\"`);\n\t\t}\n\t}\n\n\treturn parts.join(\" \");\n}\n\nfunction escapeHeaderValue(value: string): string {\n\treturn value.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"');\n}\n"],"names":["createProAuthenticationMiddleware","options","context","next","typedContext","existing","getAuthentication","skipIfAuthenticated","authenticated","strategies","result","authenticate","stopOnFailure","undefined","attachAuthentication","required","onUnauthenticated","createAuthenticationFailureResponse","createProAuthorizationMiddleware","authState","subject","getSubject","authenticatedSubject","identity","attempts","challenges","error","AthosError","code","ATHOS_ERROR_CODES","AUTH_UNAUTHENTICATED","state","set","AUTH_STATE_KEY","failure","decisionInput","getResource","resource","getEnvironment","decision","authorize","policy","ATHOS_STATE_KEYS","AUTHZ","allowed","onForbidden","createAuthorizationFailureResponse","response","json","strategy","reason","reasonCode","headerValue","formatWwwAuthenticateHeader","headers","length","map","formatChallengeInstruction","join","challenge","parts","scheme","realm","push","escapeHeaderValue","params","key","value","Object","entries","replace"],"mappings":"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"}
package/security.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { type AuthenticationResult, type AuthIdentity, type AuthStateCarrier, type ChallengeInstruction } from "@athosjs/auth";
2
+ import type { AuthorizationDecision } from "@athosjs/authz";
3
+ import { type HttpContext, type HttpMiddleware, type HttpResponse } from "@athosjs/http";
4
+ import type { ProAuthenticationMiddlewareOptions, ProAuthorizationMiddlewareOptions } from "@athosjs/types/pro";
5
+ export type { ProAuthenticationMiddlewareOptions, ProAuthorizationMiddlewareOptions };
6
+ export declare function createProAuthenticationMiddleware<TContext extends HttpContext & AuthStateCarrier, TIdentity extends AuthIdentity = AuthIdentity>(options: ProAuthenticationMiddlewareOptions<TContext, TIdentity>): HttpMiddleware;
7
+ export declare function createProAuthorizationMiddleware<TContext extends HttpContext & AuthStateCarrier, TIdentity extends AuthIdentity = AuthIdentity, TResource = unknown, TEnvironment = unknown>(options: ProAuthorizationMiddlewareOptions<TContext, TIdentity, TResource, TEnvironment>): HttpMiddleware;
8
+ export declare function createAuthenticationFailureResponse<TIdentity extends AuthIdentity = AuthIdentity>(result: AuthenticationResult<TIdentity>): HttpResponse;
9
+ export declare function createAuthorizationFailureResponse(decision: AuthorizationDecision): HttpResponse;
10
+ export declare function formatWwwAuthenticateHeader(challenges: readonly ChallengeInstruction[]): string | undefined;
11
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../../../../packages/pro/src/security.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAMrB,KAAK,oBAAoB,EAEzB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAwB,qBAAqB,EAAuB,MAAM,gBAAgB,CAAC;AAGvG,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,YAAY,EAAQ,MAAM,eAAe,CAAC;AAC/F,OAAO,KAAK,EAAE,kCAAkC,EAAE,iCAAiC,EAAE,MAAM,oBAAoB,CAAC;AAEhH,YAAY,EAAE,kCAAkC,EAAE,iCAAiC,EAAE,CAAC;AAEtF,wBAAgB,iCAAiC,CAChD,QAAQ,SAAS,WAAW,GAAG,gBAAgB,EAC/C,SAAS,SAAS,YAAY,GAAG,YAAY,EAC5C,OAAO,EAAE,kCAAkC,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,cAAc,CA6BlF;AAED,wBAAgB,gCAAgC,CAC/C,QAAQ,SAAS,WAAW,GAAG,gBAAgB,EAC/C,SAAS,SAAS,YAAY,GAAG,YAAY,EAC7C,SAAS,GAAG,OAAO,EACnB,YAAY,GAAG,OAAO,EACrB,OAAO,EAAE,iCAAiC,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,CAAC,GAAG,cAAc,CAyD1G;AAED,wBAAgB,mCAAmC,CAAC,SAAS,SAAS,YAAY,GAAG,YAAY,EAChG,MAAM,EAAE,oBAAoB,CAAC,SAAS,CAAC,GACrC,YAAY,CAyBd;AAED,wBAAgB,kCAAkC,CAAC,QAAQ,EAAE,qBAAqB,GAAG,YAAY,CAWhG;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,GAAG,SAAS,CAM3G"}