@burdenoff/be-sdk 2026.825.7 → 2026.825.9

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 (120) hide show
  1. package/dist/EventQueueFactory-J2XXPYXH.js +7 -0
  2. package/dist/{EventQueueFactory-ELT7NDXK.js.map → EventQueueFactory-J2XXPYXH.js.map} +1 -1
  3. package/dist/auth/index.js +2 -2
  4. package/dist/cache/index.js +3 -3
  5. package/dist/{chunk-AW6JUXCU.js → chunk-3UQMAUX4.js} +4 -4
  6. package/dist/{chunk-AW6JUXCU.js.map → chunk-3UQMAUX4.js.map} +1 -1
  7. package/dist/{chunk-N3YN6ZII.js → chunk-5JNHVKHG.js} +3 -3
  8. package/dist/{chunk-N3YN6ZII.js.map → chunk-5JNHVKHG.js.map} +1 -1
  9. package/dist/{chunk-7UJXIX4I.js → chunk-5NT2OEDQ.js} +3 -3
  10. package/dist/{chunk-7UJXIX4I.js.map → chunk-5NT2OEDQ.js.map} +1 -1
  11. package/dist/{chunk-OQLDXOZ3.js → chunk-6GL4SLU7.js} +3 -3
  12. package/dist/{chunk-OQLDXOZ3.js.map → chunk-6GL4SLU7.js.map} +1 -1
  13. package/dist/{chunk-L3QCRJOA.js → chunk-74Y5YD3U.js} +7 -7
  14. package/dist/{chunk-L3QCRJOA.js.map → chunk-74Y5YD3U.js.map} +1 -1
  15. package/dist/{chunk-NVVWSOY7.js → chunk-AX3UF33H.js} +3 -3
  16. package/dist/{chunk-NVVWSOY7.js.map → chunk-AX3UF33H.js.map} +1 -1
  17. package/dist/{chunk-Z3O32BW6.js → chunk-CPLFP5JK.js} +3 -3
  18. package/dist/{chunk-Z3O32BW6.js.map → chunk-CPLFP5JK.js.map} +1 -1
  19. package/dist/{chunk-XD5ZK727.js → chunk-DS3YMJ4X.js} +3 -3
  20. package/dist/{chunk-XD5ZK727.js.map → chunk-DS3YMJ4X.js.map} +1 -1
  21. package/dist/{chunk-2HANKZZM.js → chunk-ELU7VL3E.js} +3 -3
  22. package/dist/{chunk-2HANKZZM.js.map → chunk-ELU7VL3E.js.map} +1 -1
  23. package/dist/{chunk-KESVEZB2.js → chunk-FA5ROGTS.js} +3 -3
  24. package/dist/{chunk-KESVEZB2.js.map → chunk-FA5ROGTS.js.map} +1 -1
  25. package/dist/{chunk-WFVLQELZ.js → chunk-FYH5IAPR.js} +6 -6
  26. package/dist/{chunk-WFVLQELZ.js.map → chunk-FYH5IAPR.js.map} +1 -1
  27. package/dist/{chunk-RXMOV3YE.js → chunk-GJWQK3IU.js} +3 -3
  28. package/dist/{chunk-RXMOV3YE.js.map → chunk-GJWQK3IU.js.map} +1 -1
  29. package/dist/{chunk-TORD32GS.js → chunk-INAZ3PKF.js} +3 -3
  30. package/dist/{chunk-TORD32GS.js.map → chunk-INAZ3PKF.js.map} +1 -1
  31. package/dist/{chunk-UJG32VIP.js → chunk-IUJSIXMM.js} +3 -3
  32. package/dist/{chunk-UJG32VIP.js.map → chunk-IUJSIXMM.js.map} +1 -1
  33. package/dist/{chunk-VI4VSNTI.js → chunk-KJOSPVB2.js} +3 -3
  34. package/dist/{chunk-VI4VSNTI.js.map → chunk-KJOSPVB2.js.map} +1 -1
  35. package/dist/{chunk-UM32ZA3G.js → chunk-KMNSVLDS.js} +5 -5
  36. package/dist/{chunk-UM32ZA3G.js.map → chunk-KMNSVLDS.js.map} +1 -1
  37. package/dist/{chunk-VBXPFYZ5.js → chunk-KO2ZXZ7W.js} +3 -3
  38. package/dist/{chunk-VBXPFYZ5.js.map → chunk-KO2ZXZ7W.js.map} +1 -1
  39. package/dist/{chunk-VDYBUTFI.js → chunk-KW55Q6TA.js} +5 -5
  40. package/dist/{chunk-VDYBUTFI.js.map → chunk-KW55Q6TA.js.map} +1 -1
  41. package/dist/{chunk-OCYZEBOL.js → chunk-L5TDUAFN.js} +3 -3
  42. package/dist/{chunk-OCYZEBOL.js.map → chunk-L5TDUAFN.js.map} +1 -1
  43. package/dist/{chunk-S7LWYERE.js → chunk-LKCBI6B2.js} +3 -3
  44. package/dist/{chunk-S7LWYERE.js.map → chunk-LKCBI6B2.js.map} +1 -1
  45. package/dist/{chunk-LGTQ26Z2.js → chunk-MEA4BQNA.js} +3 -3
  46. package/dist/{chunk-LGTQ26Z2.js.map → chunk-MEA4BQNA.js.map} +1 -1
  47. package/dist/{chunk-QLVKMWFA.js → chunk-MWPYA2HD.js} +3 -3
  48. package/dist/{chunk-QLVKMWFA.js.map → chunk-MWPYA2HD.js.map} +1 -1
  49. package/dist/{chunk-XWVP4MC6.js → chunk-MZCBEJ67.js} +3 -3
  50. package/dist/{chunk-XWVP4MC6.js.map → chunk-MZCBEJ67.js.map} +1 -1
  51. package/dist/{chunk-URDYOM2L.js → chunk-QJN4K7LD.js} +4 -4
  52. package/dist/{chunk-URDYOM2L.js.map → chunk-QJN4K7LD.js.map} +1 -1
  53. package/dist/{chunk-CBZNP6RF.js → chunk-RU266375.js} +48 -7
  54. package/dist/chunk-RU266375.js.map +1 -0
  55. package/dist/{chunk-A6DGEZJ4.js → chunk-UD5PPGVU.js} +3 -3
  56. package/dist/{chunk-A6DGEZJ4.js.map → chunk-UD5PPGVU.js.map} +1 -1
  57. package/dist/{chunk-JNJSSBKO.js → chunk-UFXHLQ2T.js} +5 -5
  58. package/dist/{chunk-JNJSSBKO.js.map → chunk-UFXHLQ2T.js.map} +1 -1
  59. package/dist/{chunk-F5SGJ6VS.js → chunk-UNASM5VJ.js} +3 -3
  60. package/dist/{chunk-F5SGJ6VS.js.map → chunk-UNASM5VJ.js.map} +1 -1
  61. package/dist/{chunk-5LXDPGDH.js → chunk-VAT66FJA.js} +3 -3
  62. package/dist/{chunk-5LXDPGDH.js.map → chunk-VAT66FJA.js.map} +1 -1
  63. package/dist/{chunk-7E76FL2C.js → chunk-XCQN6GH7.js} +18 -10
  64. package/dist/chunk-XCQN6GH7.js.map +1 -0
  65. package/dist/{chunk-4X5WL6I3.js → chunk-XYWLCNJH.js} +5 -5
  66. package/dist/{chunk-4X5WL6I3.js.map → chunk-XYWLCNJH.js.map} +1 -1
  67. package/dist/{chunk-MX4AHK3E.js → chunk-YAQ7GNAC.js} +6 -6
  68. package/dist/{chunk-MX4AHK3E.js.map → chunk-YAQ7GNAC.js.map} +1 -1
  69. package/dist/{chunk-RNR45JQH.js → chunk-YK7C5DU6.js} +3 -3
  70. package/dist/{chunk-RNR45JQH.js.map → chunk-YK7C5DU6.js.map} +1 -1
  71. package/dist/{chunk-IC7YDBGE.js → chunk-YNDJQRI3.js} +3 -3
  72. package/dist/{chunk-IC7YDBGE.js.map → chunk-YNDJQRI3.js.map} +1 -1
  73. package/dist/{chunk-WCJIZR5Q.js → chunk-Z5BURBFZ.js} +3 -3
  74. package/dist/{chunk-WCJIZR5Q.js.map → chunk-Z5BURBFZ.js.map} +1 -1
  75. package/dist/client/internal-client.js +2 -2
  76. package/dist/database/index.js +2 -2
  77. package/dist/event-queue/index.js +6 -6
  78. package/dist/export/index.js +5 -5
  79. package/dist/feature-flags/index.js +2 -2
  80. package/dist/gateway/index.js +4 -4
  81. package/dist/gateway/security/index.js +2 -2
  82. package/dist/graph/index.js +8 -8
  83. package/dist/graphql/index.js +4 -4
  84. package/dist/graphql/services/index.js +2 -2
  85. package/dist/i18n/index.js +2 -2
  86. package/dist/{index-BtpoFSLa.d.ts → index-BLWIKXin.d.ts} +1 -1
  87. package/dist/{index-C0qWSC_Q.d.ts → index-hWpL68Vx.d.ts} +4 -2
  88. package/dist/index.d.ts +3 -3
  89. package/dist/index.js +44 -44
  90. package/dist/init/index.js +6 -6
  91. package/dist/instrumentation/index.d.ts +2 -2
  92. package/dist/instrumentation/index.js +2 -2
  93. package/dist/layer/index.js +2 -2
  94. package/dist/lifecycle/index.js +2 -2
  95. package/dist/logger/index.d.ts +1 -1
  96. package/dist/logger/index.js +1 -1
  97. package/dist/middleware/index.js +2 -2
  98. package/dist/notifications/index.js +2 -2
  99. package/dist/observability/index.js +2 -2
  100. package/dist/pino-logger-GJ2CYLD5.js +5 -0
  101. package/dist/{pino-logger-XF275Y5C.js.map → pino-logger-GJ2CYLD5.js.map} +1 -1
  102. package/dist/platform/index.js +2 -2
  103. package/dist/prisma/index.js +8 -8
  104. package/dist/rbac/index.js +2 -2
  105. package/dist/resource-caps/index.js +2 -2
  106. package/dist/server/index.js +6 -6
  107. package/dist/sharding/index.js +1 -1
  108. package/dist/sharing/index.js +2 -2
  109. package/dist/telemetry/index.d.ts +3 -3
  110. package/dist/telemetry/index.js +5 -5
  111. package/dist/temporal/index.js +2 -2
  112. package/dist/tracker/index.js +4 -4
  113. package/dist/workspace-guard-7PEZT3ZJ.js +5 -0
  114. package/dist/{workspace-guard-4BUG4ZP2.js.map → workspace-guard-7PEZT3ZJ.js.map} +1 -1
  115. package/package.json +1 -1
  116. package/dist/EventQueueFactory-ELT7NDXK.js +0 -7
  117. package/dist/chunk-7E76FL2C.js.map +0 -1
  118. package/dist/chunk-CBZNP6RF.js.map +0 -1
  119. package/dist/pino-logger-XF275Y5C.js +0 -5
  120. package/dist/workspace-guard-4BUG4ZP2.js +0 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/feature-flags/index.ts","../src/feature-flags/provider.ts","../src/feature-flags/operations-flag-gate.ts"],"names":["EVALUATE_QUERY","readPositiveIntEnv","name","fallback","raw","process","env","parsed","parseInt","Number","isFinite","FeatureFlagProvider","gatewayUrl","cacheTtlMs","failureTtlMs","requestTimeoutMs","serviceToken","serviceName","defaultActorType","cache","Map","config","cacheTtlSeconds","failureTtlSeconds","resolveBoolean","flagKey","defaultValue","context","evaluation","getEvaluation","value","reason","flagType","Boolean","variant","undefined","errorCode","resolveString","String","resolveNumber","resolveObject","isEnabled","result","workspaceId","actorType","actorId","evaluateAll","keys","evaluations","fetchEvaluations","key","set","invalidateCache","cacheKey","buildCacheKey","delete","clear","get","cached","expiresAt","Date","now","bearerToken","signServiceJwt","response","fetch","method","signal","AbortSignal","timeout","headers","Authorization","ContextManager","getCfAccessHeaders","body","JSON","stringify","query","variables","input","ok","rememberFailure","json","errors","data","evaluateFeatureFlags","ctx","ACTOR_TYPES","isRecord","isDocumentNode","Array","isArray","definitions","findExecutedOperation","document","operationName","operations","filter","definition","kind","Kind","OPERATION_DEFINITION","find","operation","coerceActorType","includes","resolveEvaluationContext","contextValue","workspace","id","actor","type","createOperationsFlagGatePlugin","options","productId","gatedOperations","Set","userMessage","provider","getProvider","onExecute","args","has","evaluationContext","logger","warn","enabled","error","Error","message","GraphQLError","extensions","code","http","status"],"mappings":";;;;;;;AAAA,IAAA,qBAAA,GAAA;;;;;;;ACuCA,IAAMA,cAAAA,GAAiB;;;;;;;;;;;;;;AAsBvB,SAASC,kBAAAA,CAAmBC,MAAcC,QAAAA,EAAgB;AACxD,EAAA,MAAMC,GAAAA,GAAMC,OAAAA,CAAQC,GAAAA,CAAIJ,IAAAA,CAAAA;AACxB,EAAA,IAAI,CAACE,KAAK,OAAOD,QAAAA;AACjB,EAAA,MAAMI,MAAAA,GAASC,QAAAA,CAASJ,GAAAA,EAAK,EAAA,CAAA;AAC7B,EAAA,OAAOK,OAAOC,QAAAA,CAASH,MAAAA,CAAAA,IAAWA,MAAAA,GAAS,IAAIA,MAAAA,GAASJ,QAAAA;AAC1D;AALSF,MAAAA,CAAAA,kBAAAA,EAAAA,oBAAAA,CAAAA;AAOF,IAAMU,sBAAN,MAAMA;EApEb;;;AAqEmBC,EAAAA,UAAAA;AACAC,EAAAA,UAAAA;AACAC,EAAAA,YAAAA;AACAC,EAAAA,gBAAAA;AACAC,EAAAA,YAAAA;AACAC,EAAAA,WAAAA;AACAC,EAAAA,gBAAAA;;AAGAC,EAAAA,KAAAA,uBAAYC,GAAAA,EAAAA;AAE7B,EAAA,WAAA,CAAYC,MAAAA,EAAmC;AAC7C,IAAA,IAAA,CAAKT,aAAaS,MAAAA,CAAOT,UAAAA;AACzB,IAAA,IAAA,CAAKC,UAAAA,GAAAA,CAAcQ,MAAAA,CAAOC,eAAAA,IAAmB,EAAA,IAAM,GAAA;AAMnD,IAAA,IAAA,CAAKP,gBAAAA,GAAmBM,MAAAA,CAAON,gBAAAA,IAAoBd,kBAAAA,CAAmB,mCAAmC,GAAA,CAAA;AAGzG,IAAA,IAAA,CAAKa,gBAAgBO,MAAAA,CAAOE,iBAAAA,IAAqBtB,kBAAAA,CAAmB,kCAAA,EAAoC,EAAA,CAAA,IAAO,GAAA;AAC/G,IAAA,IAAA,CAAKe,eAAeK,MAAAA,CAAOL,YAAAA;AAC3B,IAAA,IAAA,CAAKC,cAAcI,MAAAA,CAAOJ,WAAAA,IAAeZ,OAAAA,CAAQC,GAAAA,CAAI,cAAA,CAAA,IAAmB,kBAAA;AACxE,IAAA,IAAA,CAAKY,gBAAAA,GAAmBG,OAAOH,gBAAAA,IAAoB,SAAA;AACrD,EAAA;;;;;;;;;;;;EAcA,MAAMM,cAAAA,CACJC,OAAAA,EACAC,YAAAA,EACAC,OAAAA,EACqC;AACrC,IAAA,MAAMC,UAAAA,GAAa,MAAM,IAAA,CAAKC,aAAAA,CAAcJ,SAASE,OAAAA,CAAAA;AACrD,IAAA,IAAI,CAACC,UAAAA,EAAY;AACf,MAAA,OAAO;QACLE,KAAAA,EAAOJ,YAAAA;QACPK,MAAAA,EAAQ,SAAA;QACRC,QAAAA,EAAU;AACZ,OAAA;AACF,IAAA;AAEA,IAAA,OAAO;MACLF,KAAAA,EAAOG,OAAAA,CAAQL,WAAWE,KAAK,CAAA;AAC/BI,MAAAA,OAAAA,EAASN,WAAWM,OAAAA,IAAWC,MAAAA;AAC/BJ,MAAAA,MAAAA,EAAQH,UAAAA,CAAWG,MAAAA;AACnBC,MAAAA,QAAAA,EAAUJ,UAAAA,CAAWI,QAAAA;AACrBI,MAAAA,SAAAA,EAAWR,WAAWQ,SAAAA,IAAaD;AACrC,KAAA;AACF,EAAA;;;;EAKA,MAAME,aAAAA,CACJZ,OAAAA,EACAC,YAAAA,EACAC,OAAAA,EACoC;AACpC,IAAA,MAAMC,UAAAA,GAAa,MAAM,IAAA,CAAKC,aAAAA,CAAcJ,SAASE,OAAAA,CAAAA;AACrD,IAAA,IAAI,CAACC,UAAAA,EAAY;AACf,MAAA,OAAO;QACLE,KAAAA,EAAOJ,YAAAA;QACPK,MAAAA,EAAQ,SAAA;QACRC,QAAAA,EAAU;AACZ,OAAA;AACF,IAAA;AAEA,IAAA,OAAO;MACLF,KAAAA,EAAOQ,MAAAA,CAAOV,WAAWE,KAAK,CAAA;AAC9BI,MAAAA,OAAAA,EAASN,WAAWM,OAAAA,IAAWC,MAAAA;AAC/BJ,MAAAA,MAAAA,EAAQH,UAAAA,CAAWG,MAAAA;AACnBC,MAAAA,QAAAA,EAAUJ,UAAAA,CAAWI,QAAAA;AACrBI,MAAAA,SAAAA,EAAWR,WAAWQ,SAAAA,IAAaD;AACrC,KAAA;AACF,EAAA;;;;EAKA,MAAMI,aAAAA,CACJd,OAAAA,EACAC,YAAAA,EACAC,OAAAA,EACoC;AACpC,IAAA,MAAMC,UAAAA,GAAa,MAAM,IAAA,CAAKC,aAAAA,CAAcJ,SAASE,OAAAA,CAAAA;AACrD,IAAA,IAAI,CAACC,UAAAA,EAAY;AACf,MAAA,OAAO;QACLE,KAAAA,EAAOJ,YAAAA;QACPK,MAAAA,EAAQ,SAAA;QACRC,QAAAA,EAAU;AACZ,OAAA;AACF,IAAA;AAEA,IAAA,OAAO;MACLF,KAAAA,EAAOrB,MAAAA,CAAOmB,WAAWE,KAAK,CAAA;AAC9BI,MAAAA,OAAAA,EAASN,WAAWM,OAAAA,IAAWC,MAAAA;AAC/BJ,MAAAA,MAAAA,EAAQH,UAAAA,CAAWG,MAAAA;AACnBC,MAAAA,QAAAA,EAAUJ,UAAAA,CAAWI,QAAAA;AACrBI,MAAAA,SAAAA,EAAWR,WAAWQ,SAAAA,IAAaD;AACrC,KAAA;AACF,EAAA;;;;EAKA,MAAMK,aAAAA,CACJf,OAAAA,EACAC,YAAAA,EACAC,OAAAA,EAC+B;AAC/B,IAAA,MAAMC,UAAAA,GAAa,MAAM,IAAA,CAAKC,aAAAA,CAAcJ,SAASE,OAAAA,CAAAA;AACrD,IAAA,IAAI,CAACC,UAAAA,EAAY;AACf,MAAA,OAAO;QACLE,KAAAA,EAAOJ,YAAAA;QACPK,MAAAA,EAAQ,SAAA;QACRC,QAAAA,EAAU;AACZ,OAAA;AACF,IAAA;AAEA,IAAA,OAAO;AACLF,MAAAA,KAAAA,EAAOF,UAAAA,CAAWE,KAAAA;AAClBI,MAAAA,OAAAA,EAASN,WAAWM,OAAAA,IAAWC,MAAAA;AAC/BJ,MAAAA,MAAAA,EAAQH,UAAAA,CAAWG,MAAAA;AACnBC,MAAAA,QAAAA,EAAUJ,UAAAA,CAAWI,QAAAA;AACrBI,MAAAA,SAAAA,EAAWR,WAAWQ,SAAAA,IAAaD;AACrC,KAAA;AACF,EAAA;;;;;;;;;;;;;;;EAiBA,MAAMM,SAAAA,CAAUhB,SAAiBE,OAAAA,EAA+C;AAC9E,IAAA,MAAMe,SAAS,MAAM,IAAA,CAAKlB,cAAAA,CACxBC,OAAAA,EACA,MACAE,OAAAA,IAAW;MAAEgB,WAAAA,EAAa,QAAA;MAAUC,SAAAA,EAAW,SAAA;MAAWC,OAAAA,EAAS;KAAO,CAAA;AAE5E,IAAA,OAAOH,MAAAA,CAAOZ,KAAAA;AAChB,EAAA;;;;;EAMA,MAAMgB,WAAAA,CAAYnB,SAA4BoB,IAAAA,EAAmE;AAC/G,IAAA,MAAMC,WAAAA,GAAc,MAAM,IAAA,CAAKC,gBAAAA,CAAiBtB,SAASoB,IAAAA,CAAAA;AACzD,IAAA,MAAML,MAAAA,uBAAatB,GAAAA,EAAAA;AAEnB,IAAA,KAAA,MAAW,CAAC8B,GAAAA,EAAKtB,UAAAA,CAAAA,IAAeoB,WAAAA,EAAa;AAC3CN,MAAAA,MAAAA,CAAOS,IAAID,GAAAA,EAAK;AACdpB,QAAAA,KAAAA,EAAOF,UAAAA,CAAWE,KAAAA;AAClBI,QAAAA,OAAAA,EAASN,WAAWM,OAAAA,IAAWC,MAAAA;AAC/BJ,QAAAA,MAAAA,EAAQH,UAAAA,CAAWG,MAAAA;AACnBC,QAAAA,QAAAA,EAAUJ,UAAAA,CAAWI,QAAAA;AACrBI,QAAAA,SAAAA,EAAWR,WAAWQ,SAAAA,IAAaD;OACrC,CAAA;AACF,IAAA;AAEA,IAAA,OAAOO,MAAAA;AACT,EAAA;;;;;AAMAU,EAAAA,eAAAA,CAAgBzB,OAAAA,EAAmC;AACjD,IAAA,IAAIA,OAAAA,EAAS;AACX,MAAA,MAAM0B,QAAAA,GAAW,IAAA,CAAKC,aAAAA,CAAc3B,OAAAA,CAAAA;AACpC,MAAA,IAAA,CAAKR,KAAAA,CAAMoC,OAAOF,QAAAA,CAAAA;IACpB,CAAA,MAAO;AACL,MAAA,IAAA,CAAKlC,MAAMqC,KAAAA,EAAK;AAClB,IAAA;AACF,EAAA;;;;;;;EASA,MAAc3B,aAAAA,CAAcJ,SAAiBE,OAAAA,EAAwE;AACnH,IAAA,IAAI;AACF,MAAA,MAAMqB,WAAAA,GAAc,MAAM,IAAA,CAAKC,gBAAAA,CAAiBtB,OAAAA,CAAAA;AAChD,MAAA,OAAOqB,WAAAA,CAAYS,GAAAA,CAAIhC,OAAAA,CAAAA,IAAY,IAAA;IACrC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AACT,IAAA;AACF,EAAA;;;;EAKA,MAAcwB,gBAAAA,CACZtB,SACAoB,IAAAA,EACsC;AACtC,IAAA,MAAMM,QAAAA,GAAW,IAAA,CAAKC,aAAAA,CAAc3B,OAAAA,CAAAA;AACpC,IAAA,MAAM+B,MAAAA,GAAS,IAAA,CAAKvC,KAAAA,CAAMsC,GAAAA,CAAIJ,QAAAA,CAAAA;AAE9B,IAAA,IAAIK,MAAAA,IAAUA,MAAAA,CAAOC,SAAAA,GAAYC,IAAAA,CAAKC,KAAG,EAAI;AAC3C,MAAA,OAAOH,MAAAA,CAAOV,WAAAA;AAChB,IAAA;AAIA,IAAA,IAAI,CAACrB,SAASgB,WAAAA,EAAa;AACzB,MAAA,2BAAWvB,GAAAA,EAAAA;AACb,IAAA;AAOA,IAAA,MAAM0C,cAAc,IAAA,CAAK9C,YAAAA,IAAiB,MAAM+C,cAAAA,CAAe,IAAA,CAAK9C,WAAW,CAAA,IAAMkB,MAAAA;AAGrF,IAAA,IAAI;AACF,MAAA,MAAM6B,QAAAA,GAAW,MAAMC,KAAAA,CAAM,IAAA,CAAKrD,UAAAA,EAAY;QAC5CsD,MAAAA,EAAQ,MAAA;;;;QAIRC,MAAAA,EAAQC,WAAAA,CAAYC,OAAAA,CAAQ,IAAA,CAAKtD,gBAAgB,CAAA;QACjDuD,OAAAA,EAAS;UACP,cAAA,EAAgB,kBAAA;AAChB,UAAA,GAAI3C,QAAQkB,OAAAA,IAAW;AAAE,YAAA,YAAA,EAAclB,OAAAA,CAAQkB;AAAQ,WAAA;UACvD,cAAA,EAAgBlB,OAAAA,CAAQiB,aAAa,IAAA,CAAK1B,gBAAAA;AAC1C,UAAA,gBAAA,EAAkBS,OAAAA,CAAQgB,WAAAA;AAC1B,UAAA,GAAImB,WAAAA,IAAe;AAAES,YAAAA,aAAAA,EAAe,UAAUT,WAAAA,CAAAA;AAAc,WAAA;;;;AAI5D,UAAA,GAAGU,eAAeC,kBAAAA;AACpB,SAAA;AACAC,QAAAA,IAAAA,EAAMC,KAAKC,SAAAA,CAAU;UACnBC,KAAAA,EAAO7E,cAAAA;UACP8E,SAAAA,EAAW;YACTC,KAAAA,EAAO;AACLpC,cAAAA,WAAAA,EAAahB,OAAAA,CAAQgB,WAAAA;AACrBI,cAAAA,IAAAA,EAAMA,IAAAA,IAAQ;AAChB;AACF;SACF;OACF,CAAA;AAEA,MAAA,IAAI,CAACiB,SAASgB,EAAAA,EAAI;AAEhB,QAAA,OAAO,IAAA,CAAKC,gBAAgB5B,QAAAA,CAAAA;AAC9B,MAAA;AAEA,MAAA,MAAM6B,IAAAA,GAAQ,MAAMlB,QAAAA,CAASkB,IAAAA,EAAI;AASjC,MAAA,IAAIA,KAAKC,MAAAA,IAAU,CAACD,IAAAA,CAAKE,IAAAA,EAAMC,sBAAsBrC,WAAAA,EAAa;AAChE,QAAA,OAAO,IAAA,CAAKiC,gBAAgB5B,QAAAA,CAAAA;AAC9B,MAAA;AAEA,MAAA,MAAML,WAAAA,uBAAkB5B,GAAAA,EAAAA;AACxB,MAAA,KAAA,MAAWQ,UAAAA,IAAcsD,IAAAA,CAAKE,IAAAA,CAAKC,oBAAAA,CAAqBrC,WAAAA,EAAa;AACnEA,QAAAA,WAAAA,CAAYG,GAAAA,CAAIvB,UAAAA,CAAWsB,GAAAA,EAAKtB,UAAAA,CAAAA;AAClC,MAAA;AAGA,MAAA,IAAA,CAAKT,KAAAA,CAAMgC,IAAIE,QAAAA,EAAU;AACvBL,QAAAA,WAAAA;QACAW,SAAAA,EAAWC,IAAAA,CAAKC,GAAAA,EAAG,GAAK,IAAA,CAAKhD;OAC/B,CAAA;AAEA,MAAA,OAAOmC,WAAAA;IACT,CAAA,CAAA,MAAQ;AAIN,MAAA,OAAO,IAAA,CAAKiC,gBAAgB5B,QAAAA,CAAAA;AAC9B,IAAA;AACF,EAAA;;;;;;AAOQ4B,EAAAA,eAAAA,CAAgB5B,QAAAA,EAA+C;AACrE,IAAA,MAAML,WAAAA,uBAAkB5B,GAAAA,EAAAA;AACxB,IAAA,IAAA,CAAKD,KAAAA,CAAMgC,IAAIE,QAAAA,EAAU;AACvBL,MAAAA,WAAAA;MACAW,SAAAA,EAAWC,IAAAA,CAAKC,GAAAA,EAAG,GAAK,IAAA,CAAK/C;KAC/B,CAAA;AACA,IAAA,OAAOkC,WAAAA;AACT,EAAA;;;;;;;;;;;AAYQM,EAAAA,aAAAA,CAAc3B,OAAAA,EAAgD;AACpE,IAAA,MAAM2D,GAAAA,GAAM3D,WAAY,EAAC;AACzB,IAAA,OAAO,CAAA,EAAG2D,GAAAA,CAAI3C,WAAAA,IAAe,QAAA,CAAA,CAAA,EAAY2C,GAAAA,CAAIzC,OAAAA,IAAW,WAAA,CAAA,CAAA,EAAeyC,GAAAA,CAAI1C,SAAAA,IAAa,MAAA,CAAA,CAAA;AAC1F,EAAA;AACF;AC7UA,IAAM2C,WAAAA,GAAiC;AAAC,EAAA,MAAA;AAAQ,EAAA,KAAA;AAAO,EAAA,SAAA;AAAW,EAAA;;AAElE,SAASC,SAAS1D,KAAAA,EAAc;AAC9B,EAAA,OAAO,OAAOA,KAAAA,KAAU,QAAA,IAAYA,KAAAA,KAAU,IAAA;AAChD;AAFS0D,MAAAA,CAAAA,QAAAA,EAAAA,UAAAA,CAAAA;AAIT,SAASC,eAAe3D,KAAAA,EAAc;AACpC,EAAA,OAAO0D,SAAS1D,KAAAA,CAAAA,IAAU4D,KAAAA,CAAMC,OAAAA,CAAS7D,MAAoC8D,WAAW,CAAA;AAC1F;AAFSH,MAAAA,CAAAA,cAAAA,EAAAA,gBAAAA,CAAAA;AAKT,SAASI,qBAAAA,CAAsBC,UAAwBC,aAAAA,EAA6B;AAClF,EAAA,MAAMC,UAAAA,GAAaF,SAASF,WAAAA,CAAYK,MAAAA,CACtC,CAACC,UAAAA,KAAsDA,UAAAA,CAAWC,IAAAA,KAASC,IAAAA,CAAKC,oBAAoB,CAAA;AAGtG,EAAA,IAAIN,aAAAA,EAAe;AACjB,IAAA,OAAOC,UAAAA,CAAWM,KAAK,CAACC,SAAAA,KAAcA,UAAUrG,IAAAA,EAAM4B,KAAAA,KAAUiE,aAAAA,CAAAA,IAAkB,IAAA;AACpF,EAAA;AAEA,EAAA,OAAOC,UAAAA,CAAW,CAAA,CAAA,IAAM,IAAA;AAC1B;AAVSH,MAAAA,CAAAA,qBAAAA,EAAAA,uBAAAA,CAAAA;AAYT,SAASW,gBAAgB1E,KAAAA,EAAgC;AAGvD,EAAA,OAAOA,KAAAA,IAASyD,WAAAA,CAAYkB,QAAAA,CAAS3E,KAAAA,IAAUA,KAAAA,GAA2CK,MAAAA;AAC5F;AAJSqE,MAAAA,CAAAA,eAAAA,EAAAA,iBAAAA,CAAAA;AAWT,SAASE,yBAAyBC,YAAAA,EAAqB;AAGrD,EAAA,MAAMrB,GAAAA,GAAOE,QAAAA,CAASmB,YAAAA,CAAAA,GAAgBA,eAAe,EAAC;AACtD,EAAA,MAAMhE,WAAAA,GAAc2C,GAAAA,CAAIsB,SAAAA,EAAWC,EAAAA,IAAMvB,IAAI3C,WAAAA,IAAeR,MAAAA;AAC5D,EAAA,IAAI,CAACQ,WAAAA,EAAa;AAChB,IAAA,OAAO,IAAA;AACT,EAAA;AACA,EAAA,MAAME,OAAAA,GAAUyC,GAAAA,CAAIwB,KAAAA,EAAOD,EAAAA,IAAMvB,IAAIzC,OAAAA,IAAWV,MAAAA;AAChD,EAAA,MAAMS,YAAY4D,eAAAA,CAAgBlB,GAAAA,CAAIwB,KAAAA,EAAOC,IAAAA,IAAQzB,IAAI1C,SAAS,CAAA;AAClE,EAAA,OAAO;AACLD,IAAAA,WAAAA;AACA,IAAA,GAAIE,OAAAA,GAAU;AAAEA,MAAAA;AAAQ,KAAA,GAAI,EAAC;AAC7B,IAAA,GAAID,SAAAA,GAAY;AAAEA,MAAAA;AAAU,KAAA,GAAI;AAClC,GAAA;AACF;AAfS8D,MAAAA,CAAAA,wBAAAA,EAAAA,0BAAAA,CAAAA;AAsBF,SAASM,+BAA+BC,OAAAA,EAAwC;AACrF,EAAA,MAAM,EAAExF,OAAAA,EAASyF,SAAAA,EAAS,GAAKD,OAAAA;AAC/B,EAAA,MAAME,eAAAA,GAAkB,IAAIC,GAAAA,CAAYH,OAAAA,CAAQE,eAAAA,IAAmB;AAAC,IAAA;AAAW,GAAA,CAAA;AAC/E,EAAA,MAAME,WAAAA,GAAcJ,QAAQI,WAAAA,IAAe,0CAAA;AAE3C,EAAA,IAAIC,QAAAA,GAAWL,QAAQK,QAAAA,IAAY,IAAA;AACnC,EAAA,MAAMC,8BAAc,MAAA,CAAA,MAAA;AAClB,IAAA,IAAI,CAACD,QAAAA,EAAU;AACbA,MAAAA,QAAAA,GAAW,IAAI3G,mBAAAA,CAAoB;QACjCC,UAAAA,EACEqG,OAAAA,CAAQrG,cAAcP,OAAAA,CAAQC,GAAAA,CAAI,2BAAA,CAAA,IAAgCD,OAAAA,CAAQC,GAAAA,CAAI,wBAAA,CAAA,IAA6B,EAAA;AAC7GgB,QAAAA,eAAAA,EAAiB2F,QAAQ3F,eAAAA,IAAmB,EAAA;QAC5CJ,gBAAAA,EAAkB;OACpB,CAAA;AACF,IAAA;AACA,IAAA,OAAOoG,QAAAA;EACT,CAAA,EAVoB,aAAA,CAAA;AAYpB,EAAA,OAAO;IACL,MAAME,SAAAA,CAAU,EACdC,IAAAA,EAAI,EAQL;AACC,MAAA,IAAI,CAAChC,cAAAA,CAAegC,IAAAA,CAAK3B,QAAQ,CAAA,EAAG;AAClC,QAAA;AACF,MAAA;AAEA,MAAA,MAAMS,SAAAA,GAAYV,qBAAAA,CAAsB4B,IAAAA,CAAK3B,QAAAA,EAAU2B,KAAK1B,aAAa,CAAA;AACzE,MAAA,IAAI,CAACQ,SAAAA,IAAa,CAACY,gBAAgBO,GAAAA,CAAInB,SAAAA,CAAUA,SAAS,CAAA,EAAG;AAC3D,QAAA;AACF,MAAA;AAEA,MAAA,MAAMoB,iBAAAA,GAAoBjB,wBAAAA,CAAyBe,IAAAA,CAAKd,YAAY,CAAA;AACpE,MAAA,IAAI,CAACgB,iBAAAA,EAAmB;AAEtBC,QAAAA,MAAAA,CAAOC,KAAK,qEAAA,EAAkE;AAAEpG,UAAAA,OAAAA;AAASyF,UAAAA;SAAU,CAAA;AACnG,QAAA;AACF,MAAA;AAEA,MAAA,IAAIY,OAAAA,GAAU,IAAA;AACd,MAAA,IAAI;AACFA,QAAAA,OAAAA,GAAU,MAAMP,WAAAA,EAAAA,CAAc9E,SAAAA,CAAUhB,SAASkG,iBAAAA,CAAAA;AACnD,MAAA,CAAA,CAAA,OAASI,KAAAA,EAAO;AAEdH,QAAAA,MAAAA,CAAOC,KAAK,uEAAA,EAAoE;AAC9EpG,UAAAA,OAAAA;AACAyF,UAAAA,SAAAA;AACAa,UAAAA,KAAAA,EAAOA,KAAAA,YAAiBC,KAAAA,GAAQD,KAAAA,CAAME,OAAAA,GAAU3F,OAAOyF,KAAAA;SACzD,CAAA;AACA,QAAA;AACF,MAAA;AAEA,MAAA,IAAI,CAACD,OAAAA,EAAS;AACZF,QAAAA,MAAAA,CAAOC,KAAK,8DAAA,EAA2D;AACrEpG,UAAAA,OAAAA;AACAyF,UAAAA,SAAAA;AACAvE,UAAAA,WAAAA,EAAagF,iBAAAA,CAAkBhF;SACjC,CAAA;AACA,QAAA,MAAM,IAAIuF,aAAab,WAAAA,EAAa;UAClCc,UAAAA,EAAY;YACVC,IAAAA,EAAM,kBAAA;AACN3G,YAAAA,OAAAA;AACAyF,YAAAA,SAAAA;YACAmB,IAAAA,EAAM;cAAEC,MAAAA,EAAQ;AAAI;AACtB;SACF,CAAA;AACF,MAAA;AACF,IAAA;AACF,GAAA;AACF;AA3EgBtB,MAAAA,CAAAA,8BAAAA,EAAAA,gCAAAA,CAAAA","file":"chunk-F5SGJ6VS.js","sourcesContent":["/**\n * Feature Flags Module\n *\n * In-house feature flag evaluation for Burdenoff backend services.\n * Compatible with OpenFeature specification concepts.\n *\n * @module feature-flags\n * @category FeatureFlags\n *\n * @example\n * ```typescript\n * import { FeatureFlagProvider } from '@burdenoff/be-sdk/feature-flags';\n *\n * // Create provider (typically done once at service startup)\n * const provider = new FeatureFlagProvider({\n * gatewayUrl: process.env.GLOBAL_INT_GATEWAY_URL || 'http://global-int-gateway:4000/global/graphql',\n * cacheTtlSeconds: 60,\n * });\n *\n * // Check a boolean flag\n * const ctx = { actorId: 'user-123', actorType: 'user' as const, workspaceId: 'ws-456' };\n * const isEnabled = await provider.isEnabled('calendar.recurring-events', ctx);\n *\n * // Resolve with full details\n * const details = await provider.resolveBoolean('calendar.recurring-events', true, ctx);\n * console.log(details.value); // true\n * console.log(details.reason); // 'TARGETING_MATCH'\n * console.log(details.variant); // 'user-opted-in'\n * ```\n */\n\nexport { FeatureFlagProvider } from './provider.js';\nexport type {\n EvaluationContext,\n FeatureFlagProviderConfig,\n FlagEvaluation,\n FlagType,\n ResolutionDetails,\n} from './types.js';\n\nexport { createOperationsFlagGatePlugin } from './operations-flag-gate.js';\nexport type { OperationsFlagGatePluginOptions, GatedOperationType } from './operations-flag-gate.js';\n","/**\n * Burdenoff Feature Flags Server Provider\n *\n * Server-side feature flag provider for backend services.\n * Evaluates flags via the global-tenant-svc GraphQL API through the internal gateway.\n * Supports in-memory caching with configurable TTL.\n *\n * @module feature-flags/provider\n * @category FeatureFlags\n *\n * @example\n * ```typescript\n * import { FeatureFlagProvider } from '@burdenoff/be-sdk/feature-flags';\n *\n * const provider = new FeatureFlagProvider({\n * gatewayUrl: 'http://global-int-gateway:4000/global/graphql',\n * cacheTtlSeconds: 60,\n * });\n *\n * const isEnabled = await provider.resolveBoolean('calendar.recurring-events', false, {\n * actorId: 'user-123',\n * actorType: 'user',\n * workspaceId: 'ws-456',\n * });\n *\n * console.log(isEnabled.value); // true or false\n * console.log(isEnabled.reason); // 'TARGETING_MATCH', 'DEFAULT', etc.\n * ```\n */\n\nimport { ContextManager } from '../context/index.js';\nimport { signServiceJwt } from '../gateway/service-jwt.js';\nimport type { EvaluationContext, FeatureFlagProviderConfig, FlagEvaluation, ResolutionDetails } from './types.js';\n\ninterface CacheEntry {\n evaluations: Map<string, FlagEvaluation>;\n expiresAt: number;\n}\n\nconst EVALUATE_QUERY = `\n query EvaluateFeatureFlags($input: EvaluateFeatureFlagsInput!) {\n evaluateFeatureFlags(input: $input) {\n evaluations {\n key\n value\n variant\n reason\n flagType\n errorCode\n }\n }\n }\n`;\n\n/**\n * Burdenoff Feature Flag Server Provider\n *\n * Evaluates feature flags by querying the global-tenant-svc through\n * the internal gateway. Results are cached in-memory per workspace+actor\n * combination with a configurable TTL.\n */\nfunction readPositiveIntEnv(name: string, fallback: number): number {\n const raw = process.env[name];\n if (!raw) return fallback;\n const parsed = parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\nexport class FeatureFlagProvider {\n private readonly gatewayUrl: string;\n private readonly cacheTtlMs: number;\n private readonly failureTtlMs: number;\n private readonly requestTimeoutMs: number;\n private readonly serviceToken?: string;\n private readonly serviceName: string;\n private readonly defaultActorType: string;\n\n /** In-memory cache keyed by `${workspaceId}:${actorId}` */\n private readonly cache = new Map<string, CacheEntry>();\n\n constructor(config: FeatureFlagProviderConfig) {\n this.gatewayUrl = config.gatewayUrl;\n this.cacheTtlMs = (config.cacheTtlSeconds ?? 60) * 1000;\n // Hard per-request ceiling. Without it an unreachable gateway (NSG\n // silent-drop on the cross-environment path) left the fetch hanging for\n // the kernel's ~130s TCP connect timeout — stalling every flag-gated\n // request, and killing services that await a flag at BOOT (their ACA\n // startup probe expired → ActivationFailed).\n this.requestTimeoutMs = config.requestTimeoutMs ?? readPositiveIntEnv('FEATURE_FLAG_REQUEST_TIMEOUT_MS', 3000);\n // Negative cache so a broken gateway costs at most one timeout per\n // window instead of one per evaluation.\n this.failureTtlMs = (config.failureTtlSeconds ?? readPositiveIntEnv('FEATURE_FLAG_FAILURE_TTL_SECONDS', 15)) * 1000;\n this.serviceToken = config.serviceToken;\n this.serviceName = config.serviceName ?? process.env['SERVICE_NAME'] ?? 'burdenoff-be-sdk';\n this.defaultActorType = config.defaultActorType ?? 'service';\n }\n\n // =========================================================================\n // Public Resolution Methods (OpenFeature-compatible interface)\n // =========================================================================\n\n /**\n * Resolve a boolean feature flag\n *\n * @param flagKey - The flag key (e.g. \"calendar.recurring-events\")\n * @param defaultValue - Default value if resolution fails\n * @param context - Evaluation context with actor and workspace info\n * @returns Resolution details with the resolved boolean value\n */\n async resolveBoolean(\n flagKey: string,\n defaultValue: boolean,\n context: EvaluationContext\n ): Promise<ResolutionDetails<boolean>> {\n const evaluation = await this.getEvaluation(flagKey, context);\n if (!evaluation) {\n return {\n value: defaultValue,\n reason: 'DEFAULT',\n flagType: 'BOOLEAN',\n };\n }\n\n return {\n value: Boolean(evaluation.value),\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n };\n }\n\n /**\n * Resolve a string feature flag\n */\n async resolveString(\n flagKey: string,\n defaultValue: string,\n context: EvaluationContext\n ): Promise<ResolutionDetails<string>> {\n const evaluation = await this.getEvaluation(flagKey, context);\n if (!evaluation) {\n return {\n value: defaultValue,\n reason: 'DEFAULT',\n flagType: 'STRING',\n };\n }\n\n return {\n value: String(evaluation.value),\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n };\n }\n\n /**\n * Resolve a number feature flag\n */\n async resolveNumber(\n flagKey: string,\n defaultValue: number,\n context: EvaluationContext\n ): Promise<ResolutionDetails<number>> {\n const evaluation = await this.getEvaluation(flagKey, context);\n if (!evaluation) {\n return {\n value: defaultValue,\n reason: 'DEFAULT',\n flagType: 'NUMBER',\n };\n }\n\n return {\n value: Number(evaluation.value),\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n };\n }\n\n /**\n * Resolve an object (JSON) feature flag\n */\n async resolveObject<T extends Record<string, unknown>>(\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext\n ): Promise<ResolutionDetails<T>> {\n const evaluation = await this.getEvaluation(flagKey, context);\n if (!evaluation) {\n return {\n value: defaultValue,\n reason: 'DEFAULT',\n flagType: 'JSON',\n };\n }\n\n return {\n value: evaluation.value as T,\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n };\n }\n\n // =========================================================================\n // Convenience Methods\n // =========================================================================\n\n /**\n * Quick boolean check — returns just the value.\n * Defaults to `true` (default-allow philosophy) if the flag is not found.\n *\n * @example\n * ```typescript\n * if (await provider.isEnabled('calendar.recurring-events', ctx)) {\n * // Feature is enabled\n * }\n * ```\n */\n async isEnabled(flagKey: string, context?: EvaluationContext): Promise<boolean> {\n const result = await this.resolveBoolean(\n flagKey,\n true,\n context ?? { workspaceId: 'system', actorType: 'service', actorId: 'boot' }\n );\n return result.value;\n }\n\n /**\n * Bulk evaluate multiple flags at once.\n * Returns a map of key -> ResolutionDetails.\n */\n async evaluateAll(context: EvaluationContext, keys?: string[]): Promise<Map<string, ResolutionDetails<unknown>>> {\n const evaluations = await this.fetchEvaluations(context, keys);\n const result = new Map<string, ResolutionDetails<unknown>>();\n\n for (const [key, evaluation] of evaluations) {\n result.set(key, {\n value: evaluation.value,\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n });\n }\n\n return result;\n }\n\n /**\n * Invalidate the cache for a specific workspace+actor combination,\n * or all cache entries if no context is provided.\n */\n invalidateCache(context?: EvaluationContext): void {\n if (context) {\n const cacheKey = this.buildCacheKey(context);\n this.cache.delete(cacheKey);\n } else {\n this.cache.clear();\n }\n }\n\n // =========================================================================\n // Private Methods\n // =========================================================================\n\n /**\n * Get a single flag evaluation, fetching from cache or API\n */\n private async getEvaluation(flagKey: string, context: EvaluationContext | undefined): Promise<FlagEvaluation | null> {\n try {\n const evaluations = await this.fetchEvaluations(context);\n return evaluations.get(flagKey) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Fetch flag evaluations — uses cache if available, otherwise calls the API\n */\n private async fetchEvaluations(\n context: EvaluationContext | undefined,\n keys?: string[]\n ): Promise<Map<string, FlagEvaluation>> {\n const cacheKey = this.buildCacheKey(context);\n const cached = this.cache.get(cacheKey);\n\n if (cached && cached.expiresAt > Date.now()) {\n return cached.evaluations;\n }\n\n // Without a workspace context there's nothing the backend can evaluate\n // against — fall through to caller defaults instead of hitting the API.\n if (!context?.workspaceId) {\n return new Map();\n }\n\n // Cross-layer flag evaluation transits the global PUBLIC gateway, which\n // strips raw actor headers unless the request carries a valid JWT. Use an\n // explicit serviceToken if provided, otherwise mint a short-lived `service`\n // actor JWT (no-op when SERVICE_JWT_SECRET is unset → falls back to header\n // context for same-env/internal-gateway evaluation).\n const bearerToken = this.serviceToken ?? (await signServiceJwt(this.serviceName)) ?? undefined;\n\n // Fetch from API\n try {\n const response = await fetch(this.gatewayUrl, {\n method: 'POST',\n // Bounded: an unreachable gateway must cost milliseconds-to-seconds,\n // never the kernel's TCP connect timeout. On abort the catch below\n // negative-caches and callers fall back to their defaults.\n signal: AbortSignal.timeout(this.requestTimeoutMs),\n headers: {\n 'Content-Type': 'application/json',\n ...(context.actorId && { 'x-actor-id': context.actorId }),\n 'x-actor-type': context.actorType ?? this.defaultActorType,\n 'x-workspace-id': context.workspaceId,\n ...(bearerToken && { Authorization: `Bearer ${bearerToken}` }),\n // Re-present the inbound CF Access service token when the flag check\n // runs against a CF-Access-gated public gateway (alpha). No-op when\n // request context carries no CF creds (local dev, production).\n ...ContextManager.getCfAccessHeaders(),\n },\n body: JSON.stringify({\n query: EVALUATE_QUERY,\n variables: {\n input: {\n workspaceId: context.workspaceId,\n keys: keys ?? null,\n },\n },\n }),\n });\n\n if (!response.ok) {\n // Return empty map on error — default-allow handled by callers\n return this.rememberFailure(cacheKey);\n }\n\n const json = (await response.json()) as {\n data?: {\n evaluateFeatureFlags?: {\n evaluations?: FlagEvaluation[];\n };\n };\n errors?: Array<{ message: string }>;\n };\n\n if (json.errors || !json.data?.evaluateFeatureFlags?.evaluations) {\n return this.rememberFailure(cacheKey);\n }\n\n const evaluations = new Map<string, FlagEvaluation>();\n for (const evaluation of json.data.evaluateFeatureFlags.evaluations) {\n evaluations.set(evaluation.key, evaluation);\n }\n\n // Cache the results\n this.cache.set(cacheKey, {\n evaluations,\n expiresAt: Date.now() + this.cacheTtlMs,\n });\n\n return evaluations;\n } catch {\n // On network error/timeout, return empty map (default-allow handled by\n // callers) and negative-cache so the next evaluations in the window\n // skip the doomed request entirely.\n return this.rememberFailure(cacheKey);\n }\n }\n\n /**\n * Negative-cache a failed fetch: remember an empty evaluation set for\n * `failureTtlMs` so a broken/unreachable gateway costs at most one request\n * timeout per window instead of one per flag evaluation.\n */\n private rememberFailure(cacheKey: string): Map<string, FlagEvaluation> {\n const evaluations = new Map<string, FlagEvaluation>();\n this.cache.set(cacheKey, {\n evaluations,\n expiresAt: Date.now() + this.failureTtlMs,\n });\n return evaluations;\n }\n\n /**\n * Build a cache key from the evaluation context.\n *\n * Safe against undefined/null context — callers like isEnabled() may\n * pass no context during service boot (e.g. checking a default-allow\n * feature flag at startup before the first request builds a real\n * actor context). Without the guard, isEnabled(flag) used to throw\n * \"undefined is not an object (evaluating 'context.workspaceId')\"\n * and crash the svc at startServer().\n */\n private buildCacheKey(context: EvaluationContext | undefined): string {\n const ctx = context ?? ({} as EvaluationContext);\n return `${ctx.workspaceId ?? 'system'}:${ctx.actorId ?? 'anonymous'}:${ctx.actorType ?? 'user'}`;\n }\n}\n","/**\n * Operations Feature-Flag Gate Plugin\n *\n * GraphQL-Yoga/envelop plugin factory that short-circuits GraphQL operations\n * when a product's operations feature flag is OFF, returning a clean typed\n * `FEATURE_DISABLED` (HTTP 403) error before any resolver runs.\n *\n * This is the shared, fleet-wide replacement for the per-service inline\n * `operations-feature-flag` / `feature-flag-gate` plugins (movethewheels,\n * manufacturedops, …). By default it gates MUTATIONS only; queries and\n * subscriptions pass through.\n *\n * Default-allow philosophy (matches {@link FeatureFlagProvider.isEnabled}): if\n * there is no workspace context, or the flag service is unreachable / the flag\n * is unknown, the operation is ALLOWED. A flag must be explicitly disabled for\n * the workspace to block traffic.\n *\n * @module feature-flags/operations-flag-gate\n * @category FeatureFlags\n *\n * @example\n * ```typescript\n * import { createOperationsFlagGatePlugin } from '@burdenoff/be-sdk/feature-flags';\n *\n * yogaPlugins: [\n * createOperationsFlagGatePlugin({\n * flagKey: 'movethewheels.operations',\n * productId: 'movethewheels',\n * }),\n * useGraphQLModules(application),\n * ];\n * ```\n */\n\nimport { type DocumentNode, GraphQLError, Kind, type OperationDefinitionNode } from 'graphql';\n\nimport { logger } from '../logger/index.js';\nimport type { YogaPlugin } from '../server/index.js';\nimport { FeatureFlagProvider } from './provider.js';\nimport type { EvaluationContext } from './types.js';\n\n/** GraphQL operation types that a gate can be configured to short-circuit. */\nexport type GatedOperationType = 'query' | 'mutation' | 'subscription';\n\nexport interface OperationsFlagGatePluginOptions {\n /** Feature flag key that gates the operations (e.g. `'movethewheels.operations'`). */\n flagKey: string;\n /** Product identifier this gate protects. Surfaced in the error extensions + logs. */\n productId: string;\n /**\n * Provider used to evaluate the flag. When omitted, a {@link FeatureFlagProvider}\n * is lazily built from `gatewayUrl` (or `GLOBAL_PUBLIC_GATEWAY_URL` /\n * `GLOBAL_INT_GATEWAY_URL`).\n */\n provider?: FeatureFlagProvider;\n /** Gateway URL for the lazily-built default provider. Ignored when `provider` is set. */\n gatewayUrl?: string;\n /** Cache TTL (seconds) for the lazily-built default provider. Default: 60. */\n cacheTtlSeconds?: number;\n /** Which operation types to gate. Default: `['mutation']`. */\n gatedOperations?: readonly GatedOperationType[];\n /** Override the user-facing error message shown when the flag is disabled. */\n userMessage?: string;\n}\n\n/** Actor/workspace fields the gate reads off the GraphQL context (either shape). */\ninterface GateContextShape {\n workspace?: { id?: string | null } | null;\n actor?: { id?: string | null; type?: string | null } | null;\n workspaceId?: string | null;\n actorId?: string | null;\n actorType?: string | null;\n}\n\nconst ACTOR_TYPES: readonly string[] = ['user', 'app', 'service', 'super_admin'];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isDocumentNode(value: unknown): value is DocumentNode {\n return isRecord(value) && Array.isArray((value as { definitions?: unknown }).definitions);\n}\n\n/** Find the operation that will actually execute for this request. */\nfunction findExecutedOperation(document: DocumentNode, operationName?: string | null): OperationDefinitionNode | null {\n const operations = document.definitions.filter(\n (definition): definition is OperationDefinitionNode => definition.kind === Kind.OPERATION_DEFINITION\n );\n\n if (operationName) {\n return operations.find((operation) => operation.name?.value === operationName) ?? null;\n }\n // Unnamed / single-operation request executes the first (only) operation.\n return operations[0] ?? null;\n}\n\nfunction coerceActorType(value: string | null | undefined): EvaluationContext['actorType'] {\n // Cast is sound: only reached after `ACTOR_TYPES.includes(value)` proves the\n // string is one of the known actor-type literals.\n return value && ACTOR_TYPES.includes(value) ? (value as EvaluationContext['actorType']) : undefined;\n}\n\n/**\n * Build the flag {@link EvaluationContext} from the GraphQL context, tolerating\n * both the nested (`workspace.id` / `actor.id`) and flat (`workspaceId` /\n * `actorId`) shapes. Returns `null` when no workspace can be resolved.\n */\nfunction resolveEvaluationContext(contextValue: unknown): EvaluationContext | null {\n // Cast to the fully-optional GateContextShape after the record guard; every\n // field is read defensively with optional chaining below.\n const ctx = (isRecord(contextValue) ? contextValue : {}) as GateContextShape;\n const workspaceId = ctx.workspace?.id ?? ctx.workspaceId ?? undefined;\n if (!workspaceId) {\n return null;\n }\n const actorId = ctx.actor?.id ?? ctx.actorId ?? undefined;\n const actorType = coerceActorType(ctx.actor?.type ?? ctx.actorType);\n return {\n workspaceId,\n ...(actorId ? { actorId } : {}),\n ...(actorType ? { actorType } : {}),\n };\n}\n\n/**\n * Create a GraphQL-Yoga/envelop plugin that gates operations behind a product\n * feature flag. Returns a {@link YogaPlugin} ready to drop into a service's\n * `yogaPlugins` array.\n */\nexport function createOperationsFlagGatePlugin(options: OperationsFlagGatePluginOptions): YogaPlugin {\n const { flagKey, productId } = options;\n const gatedOperations = new Set<string>(options.gatedOperations ?? ['mutation']);\n const userMessage = options.userMessage ?? 'This operation is currently unavailable.';\n\n let provider = options.provider ?? null;\n const getProvider = (): FeatureFlagProvider => {\n if (!provider) {\n provider = new FeatureFlagProvider({\n gatewayUrl:\n options.gatewayUrl ?? process.env['GLOBAL_PUBLIC_GATEWAY_URL'] ?? process.env['GLOBAL_INT_GATEWAY_URL'] ?? '',\n cacheTtlSeconds: options.cacheTtlSeconds ?? 60,\n defaultActorType: 'service',\n });\n }\n return provider;\n };\n\n return {\n async onExecute({\n args,\n }: {\n args: {\n document?: unknown;\n operationName?: string | null;\n variableValues?: Record<string, unknown>;\n contextValue?: unknown;\n };\n }): Promise<void> {\n if (!isDocumentNode(args.document)) {\n return;\n }\n\n const operation = findExecutedOperation(args.document, args.operationName);\n if (!operation || !gatedOperations.has(operation.operation)) {\n return; // Not a gated operation type — allow.\n }\n\n const evaluationContext = resolveEvaluationContext(args.contextValue);\n if (!evaluationContext) {\n // No workspace context to evaluate against → default-allow.\n logger.warn('[OperationsFlagGate] no workspace context — allowing operation', { flagKey, productId });\n return;\n }\n\n let enabled = true;\n try {\n enabled = await getProvider().isEnabled(flagKey, evaluationContext);\n } catch (error) {\n // Never let a flag-service failure block traffic (default-allow).\n logger.warn('[OperationsFlagGate] flag evaluation failed — allowing operation', {\n flagKey,\n productId,\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n\n if (!enabled) {\n logger.warn('[OperationsFlagGate] flag disabled — blocking operation', {\n flagKey,\n productId,\n workspaceId: evaluationContext.workspaceId,\n });\n throw new GraphQLError(userMessage, {\n extensions: {\n code: 'FEATURE_DISABLED',\n flagKey,\n productId,\n http: { status: 403 },\n },\n });\n }\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/feature-flags/index.ts","../src/feature-flags/provider.ts","../src/feature-flags/operations-flag-gate.ts"],"names":["EVALUATE_QUERY","readPositiveIntEnv","name","fallback","raw","process","env","parsed","parseInt","Number","isFinite","FeatureFlagProvider","gatewayUrl","cacheTtlMs","failureTtlMs","requestTimeoutMs","serviceToken","serviceName","defaultActorType","cache","Map","config","cacheTtlSeconds","failureTtlSeconds","resolveBoolean","flagKey","defaultValue","context","evaluation","getEvaluation","value","reason","flagType","Boolean","variant","undefined","errorCode","resolveString","String","resolveNumber","resolveObject","isEnabled","result","workspaceId","actorType","actorId","evaluateAll","keys","evaluations","fetchEvaluations","key","set","invalidateCache","cacheKey","buildCacheKey","delete","clear","get","cached","expiresAt","Date","now","bearerToken","signServiceJwt","response","fetch","method","signal","AbortSignal","timeout","headers","Authorization","ContextManager","getCfAccessHeaders","body","JSON","stringify","query","variables","input","ok","rememberFailure","json","errors","data","evaluateFeatureFlags","ctx","ACTOR_TYPES","isRecord","isDocumentNode","Array","isArray","definitions","findExecutedOperation","document","operationName","operations","filter","definition","kind","Kind","OPERATION_DEFINITION","find","operation","coerceActorType","includes","resolveEvaluationContext","contextValue","workspace","id","actor","type","createOperationsFlagGatePlugin","options","productId","gatedOperations","Set","userMessage","provider","getProvider","onExecute","args","has","evaluationContext","logger","warn","enabled","error","Error","message","GraphQLError","extensions","code","http","status"],"mappings":"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","file":"chunk-UNASM5VJ.js","sourcesContent":["/**\n * Feature Flags Module\n *\n * In-house feature flag evaluation for Burdenoff backend services.\n * Compatible with OpenFeature specification concepts.\n *\n * @module feature-flags\n * @category FeatureFlags\n *\n * @example\n * ```typescript\n * import { FeatureFlagProvider } from '@burdenoff/be-sdk/feature-flags';\n *\n * // Create provider (typically done once at service startup)\n * const provider = new FeatureFlagProvider({\n * gatewayUrl: process.env.GLOBAL_INT_GATEWAY_URL || 'http://global-int-gateway:4000/global/graphql',\n * cacheTtlSeconds: 60,\n * });\n *\n * // Check a boolean flag\n * const ctx = { actorId: 'user-123', actorType: 'user' as const, workspaceId: 'ws-456' };\n * const isEnabled = await provider.isEnabled('calendar.recurring-events', ctx);\n *\n * // Resolve with full details\n * const details = await provider.resolveBoolean('calendar.recurring-events', true, ctx);\n * console.log(details.value); // true\n * console.log(details.reason); // 'TARGETING_MATCH'\n * console.log(details.variant); // 'user-opted-in'\n * ```\n */\n\nexport { FeatureFlagProvider } from './provider.js';\nexport type {\n EvaluationContext,\n FeatureFlagProviderConfig,\n FlagEvaluation,\n FlagType,\n ResolutionDetails,\n} from './types.js';\n\nexport { createOperationsFlagGatePlugin } from './operations-flag-gate.js';\nexport type { OperationsFlagGatePluginOptions, GatedOperationType } from './operations-flag-gate.js';\n","/**\n * Burdenoff Feature Flags Server Provider\n *\n * Server-side feature flag provider for backend services.\n * Evaluates flags via the global-tenant-svc GraphQL API through the internal gateway.\n * Supports in-memory caching with configurable TTL.\n *\n * @module feature-flags/provider\n * @category FeatureFlags\n *\n * @example\n * ```typescript\n * import { FeatureFlagProvider } from '@burdenoff/be-sdk/feature-flags';\n *\n * const provider = new FeatureFlagProvider({\n * gatewayUrl: 'http://global-int-gateway:4000/global/graphql',\n * cacheTtlSeconds: 60,\n * });\n *\n * const isEnabled = await provider.resolveBoolean('calendar.recurring-events', false, {\n * actorId: 'user-123',\n * actorType: 'user',\n * workspaceId: 'ws-456',\n * });\n *\n * console.log(isEnabled.value); // true or false\n * console.log(isEnabled.reason); // 'TARGETING_MATCH', 'DEFAULT', etc.\n * ```\n */\n\nimport { ContextManager } from '../context/index.js';\nimport { signServiceJwt } from '../gateway/service-jwt.js';\nimport type { EvaluationContext, FeatureFlagProviderConfig, FlagEvaluation, ResolutionDetails } from './types.js';\n\ninterface CacheEntry {\n evaluations: Map<string, FlagEvaluation>;\n expiresAt: number;\n}\n\nconst EVALUATE_QUERY = `\n query EvaluateFeatureFlags($input: EvaluateFeatureFlagsInput!) {\n evaluateFeatureFlags(input: $input) {\n evaluations {\n key\n value\n variant\n reason\n flagType\n errorCode\n }\n }\n }\n`;\n\n/**\n * Burdenoff Feature Flag Server Provider\n *\n * Evaluates feature flags by querying the global-tenant-svc through\n * the internal gateway. Results are cached in-memory per workspace+actor\n * combination with a configurable TTL.\n */\nfunction readPositiveIntEnv(name: string, fallback: number): number {\n const raw = process.env[name];\n if (!raw) return fallback;\n const parsed = parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\nexport class FeatureFlagProvider {\n private readonly gatewayUrl: string;\n private readonly cacheTtlMs: number;\n private readonly failureTtlMs: number;\n private readonly requestTimeoutMs: number;\n private readonly serviceToken?: string;\n private readonly serviceName: string;\n private readonly defaultActorType: string;\n\n /** In-memory cache keyed by `${workspaceId}:${actorId}` */\n private readonly cache = new Map<string, CacheEntry>();\n\n constructor(config: FeatureFlagProviderConfig) {\n this.gatewayUrl = config.gatewayUrl;\n this.cacheTtlMs = (config.cacheTtlSeconds ?? 60) * 1000;\n // Hard per-request ceiling. Without it an unreachable gateway (NSG\n // silent-drop on the cross-environment path) left the fetch hanging for\n // the kernel's ~130s TCP connect timeout — stalling every flag-gated\n // request, and killing services that await a flag at BOOT (their ACA\n // startup probe expired → ActivationFailed).\n this.requestTimeoutMs = config.requestTimeoutMs ?? readPositiveIntEnv('FEATURE_FLAG_REQUEST_TIMEOUT_MS', 3000);\n // Negative cache so a broken gateway costs at most one timeout per\n // window instead of one per evaluation.\n this.failureTtlMs = (config.failureTtlSeconds ?? readPositiveIntEnv('FEATURE_FLAG_FAILURE_TTL_SECONDS', 15)) * 1000;\n this.serviceToken = config.serviceToken;\n this.serviceName = config.serviceName ?? process.env['SERVICE_NAME'] ?? 'burdenoff-be-sdk';\n this.defaultActorType = config.defaultActorType ?? 'service';\n }\n\n // =========================================================================\n // Public Resolution Methods (OpenFeature-compatible interface)\n // =========================================================================\n\n /**\n * Resolve a boolean feature flag\n *\n * @param flagKey - The flag key (e.g. \"calendar.recurring-events\")\n * @param defaultValue - Default value if resolution fails\n * @param context - Evaluation context with actor and workspace info\n * @returns Resolution details with the resolved boolean value\n */\n async resolveBoolean(\n flagKey: string,\n defaultValue: boolean,\n context: EvaluationContext\n ): Promise<ResolutionDetails<boolean>> {\n const evaluation = await this.getEvaluation(flagKey, context);\n if (!evaluation) {\n return {\n value: defaultValue,\n reason: 'DEFAULT',\n flagType: 'BOOLEAN',\n };\n }\n\n return {\n value: Boolean(evaluation.value),\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n };\n }\n\n /**\n * Resolve a string feature flag\n */\n async resolveString(\n flagKey: string,\n defaultValue: string,\n context: EvaluationContext\n ): Promise<ResolutionDetails<string>> {\n const evaluation = await this.getEvaluation(flagKey, context);\n if (!evaluation) {\n return {\n value: defaultValue,\n reason: 'DEFAULT',\n flagType: 'STRING',\n };\n }\n\n return {\n value: String(evaluation.value),\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n };\n }\n\n /**\n * Resolve a number feature flag\n */\n async resolveNumber(\n flagKey: string,\n defaultValue: number,\n context: EvaluationContext\n ): Promise<ResolutionDetails<number>> {\n const evaluation = await this.getEvaluation(flagKey, context);\n if (!evaluation) {\n return {\n value: defaultValue,\n reason: 'DEFAULT',\n flagType: 'NUMBER',\n };\n }\n\n return {\n value: Number(evaluation.value),\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n };\n }\n\n /**\n * Resolve an object (JSON) feature flag\n */\n async resolveObject<T extends Record<string, unknown>>(\n flagKey: string,\n defaultValue: T,\n context: EvaluationContext\n ): Promise<ResolutionDetails<T>> {\n const evaluation = await this.getEvaluation(flagKey, context);\n if (!evaluation) {\n return {\n value: defaultValue,\n reason: 'DEFAULT',\n flagType: 'JSON',\n };\n }\n\n return {\n value: evaluation.value as T,\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n };\n }\n\n // =========================================================================\n // Convenience Methods\n // =========================================================================\n\n /**\n * Quick boolean check — returns just the value.\n * Defaults to `true` (default-allow philosophy) if the flag is not found.\n *\n * @example\n * ```typescript\n * if (await provider.isEnabled('calendar.recurring-events', ctx)) {\n * // Feature is enabled\n * }\n * ```\n */\n async isEnabled(flagKey: string, context?: EvaluationContext): Promise<boolean> {\n const result = await this.resolveBoolean(\n flagKey,\n true,\n context ?? { workspaceId: 'system', actorType: 'service', actorId: 'boot' }\n );\n return result.value;\n }\n\n /**\n * Bulk evaluate multiple flags at once.\n * Returns a map of key -> ResolutionDetails.\n */\n async evaluateAll(context: EvaluationContext, keys?: string[]): Promise<Map<string, ResolutionDetails<unknown>>> {\n const evaluations = await this.fetchEvaluations(context, keys);\n const result = new Map<string, ResolutionDetails<unknown>>();\n\n for (const [key, evaluation] of evaluations) {\n result.set(key, {\n value: evaluation.value,\n variant: evaluation.variant ?? undefined,\n reason: evaluation.reason,\n flagType: evaluation.flagType,\n errorCode: evaluation.errorCode ?? undefined,\n });\n }\n\n return result;\n }\n\n /**\n * Invalidate the cache for a specific workspace+actor combination,\n * or all cache entries if no context is provided.\n */\n invalidateCache(context?: EvaluationContext): void {\n if (context) {\n const cacheKey = this.buildCacheKey(context);\n this.cache.delete(cacheKey);\n } else {\n this.cache.clear();\n }\n }\n\n // =========================================================================\n // Private Methods\n // =========================================================================\n\n /**\n * Get a single flag evaluation, fetching from cache or API\n */\n private async getEvaluation(flagKey: string, context: EvaluationContext | undefined): Promise<FlagEvaluation | null> {\n try {\n const evaluations = await this.fetchEvaluations(context);\n return evaluations.get(flagKey) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Fetch flag evaluations — uses cache if available, otherwise calls the API\n */\n private async fetchEvaluations(\n context: EvaluationContext | undefined,\n keys?: string[]\n ): Promise<Map<string, FlagEvaluation>> {\n const cacheKey = this.buildCacheKey(context);\n const cached = this.cache.get(cacheKey);\n\n if (cached && cached.expiresAt > Date.now()) {\n return cached.evaluations;\n }\n\n // Without a workspace context there's nothing the backend can evaluate\n // against — fall through to caller defaults instead of hitting the API.\n if (!context?.workspaceId) {\n return new Map();\n }\n\n // Cross-layer flag evaluation transits the global PUBLIC gateway, which\n // strips raw actor headers unless the request carries a valid JWT. Use an\n // explicit serviceToken if provided, otherwise mint a short-lived `service`\n // actor JWT (no-op when SERVICE_JWT_SECRET is unset → falls back to header\n // context for same-env/internal-gateway evaluation).\n const bearerToken = this.serviceToken ?? (await signServiceJwt(this.serviceName)) ?? undefined;\n\n // Fetch from API\n try {\n const response = await fetch(this.gatewayUrl, {\n method: 'POST',\n // Bounded: an unreachable gateway must cost milliseconds-to-seconds,\n // never the kernel's TCP connect timeout. On abort the catch below\n // negative-caches and callers fall back to their defaults.\n signal: AbortSignal.timeout(this.requestTimeoutMs),\n headers: {\n 'Content-Type': 'application/json',\n ...(context.actorId && { 'x-actor-id': context.actorId }),\n 'x-actor-type': context.actorType ?? this.defaultActorType,\n 'x-workspace-id': context.workspaceId,\n ...(bearerToken && { Authorization: `Bearer ${bearerToken}` }),\n // Re-present the inbound CF Access service token when the flag check\n // runs against a CF-Access-gated public gateway (alpha). No-op when\n // request context carries no CF creds (local dev, production).\n ...ContextManager.getCfAccessHeaders(),\n },\n body: JSON.stringify({\n query: EVALUATE_QUERY,\n variables: {\n input: {\n workspaceId: context.workspaceId,\n keys: keys ?? null,\n },\n },\n }),\n });\n\n if (!response.ok) {\n // Return empty map on error — default-allow handled by callers\n return this.rememberFailure(cacheKey);\n }\n\n const json = (await response.json()) as {\n data?: {\n evaluateFeatureFlags?: {\n evaluations?: FlagEvaluation[];\n };\n };\n errors?: Array<{ message: string }>;\n };\n\n if (json.errors || !json.data?.evaluateFeatureFlags?.evaluations) {\n return this.rememberFailure(cacheKey);\n }\n\n const evaluations = new Map<string, FlagEvaluation>();\n for (const evaluation of json.data.evaluateFeatureFlags.evaluations) {\n evaluations.set(evaluation.key, evaluation);\n }\n\n // Cache the results\n this.cache.set(cacheKey, {\n evaluations,\n expiresAt: Date.now() + this.cacheTtlMs,\n });\n\n return evaluations;\n } catch {\n // On network error/timeout, return empty map (default-allow handled by\n // callers) and negative-cache so the next evaluations in the window\n // skip the doomed request entirely.\n return this.rememberFailure(cacheKey);\n }\n }\n\n /**\n * Negative-cache a failed fetch: remember an empty evaluation set for\n * `failureTtlMs` so a broken/unreachable gateway costs at most one request\n * timeout per window instead of one per flag evaluation.\n */\n private rememberFailure(cacheKey: string): Map<string, FlagEvaluation> {\n const evaluations = new Map<string, FlagEvaluation>();\n this.cache.set(cacheKey, {\n evaluations,\n expiresAt: Date.now() + this.failureTtlMs,\n });\n return evaluations;\n }\n\n /**\n * Build a cache key from the evaluation context.\n *\n * Safe against undefined/null context — callers like isEnabled() may\n * pass no context during service boot (e.g. checking a default-allow\n * feature flag at startup before the first request builds a real\n * actor context). Without the guard, isEnabled(flag) used to throw\n * \"undefined is not an object (evaluating 'context.workspaceId')\"\n * and crash the svc at startServer().\n */\n private buildCacheKey(context: EvaluationContext | undefined): string {\n const ctx = context ?? ({} as EvaluationContext);\n return `${ctx.workspaceId ?? 'system'}:${ctx.actorId ?? 'anonymous'}:${ctx.actorType ?? 'user'}`;\n }\n}\n","/**\n * Operations Feature-Flag Gate Plugin\n *\n * GraphQL-Yoga/envelop plugin factory that short-circuits GraphQL operations\n * when a product's operations feature flag is OFF, returning a clean typed\n * `FEATURE_DISABLED` (HTTP 403) error before any resolver runs.\n *\n * This is the shared, fleet-wide replacement for the per-service inline\n * `operations-feature-flag` / `feature-flag-gate` plugins (movethewheels,\n * manufacturedops, …). By default it gates MUTATIONS only; queries and\n * subscriptions pass through.\n *\n * Default-allow philosophy (matches {@link FeatureFlagProvider.isEnabled}): if\n * there is no workspace context, or the flag service is unreachable / the flag\n * is unknown, the operation is ALLOWED. A flag must be explicitly disabled for\n * the workspace to block traffic.\n *\n * @module feature-flags/operations-flag-gate\n * @category FeatureFlags\n *\n * @example\n * ```typescript\n * import { createOperationsFlagGatePlugin } from '@burdenoff/be-sdk/feature-flags';\n *\n * yogaPlugins: [\n * createOperationsFlagGatePlugin({\n * flagKey: 'movethewheels.operations',\n * productId: 'movethewheels',\n * }),\n * useGraphQLModules(application),\n * ];\n * ```\n */\n\nimport { type DocumentNode, GraphQLError, Kind, type OperationDefinitionNode } from 'graphql';\n\nimport { logger } from '../logger/index.js';\nimport type { YogaPlugin } from '../server/index.js';\nimport { FeatureFlagProvider } from './provider.js';\nimport type { EvaluationContext } from './types.js';\n\n/** GraphQL operation types that a gate can be configured to short-circuit. */\nexport type GatedOperationType = 'query' | 'mutation' | 'subscription';\n\nexport interface OperationsFlagGatePluginOptions {\n /** Feature flag key that gates the operations (e.g. `'movethewheels.operations'`). */\n flagKey: string;\n /** Product identifier this gate protects. Surfaced in the error extensions + logs. */\n productId: string;\n /**\n * Provider used to evaluate the flag. When omitted, a {@link FeatureFlagProvider}\n * is lazily built from `gatewayUrl` (or `GLOBAL_PUBLIC_GATEWAY_URL` /\n * `GLOBAL_INT_GATEWAY_URL`).\n */\n provider?: FeatureFlagProvider;\n /** Gateway URL for the lazily-built default provider. Ignored when `provider` is set. */\n gatewayUrl?: string;\n /** Cache TTL (seconds) for the lazily-built default provider. Default: 60. */\n cacheTtlSeconds?: number;\n /** Which operation types to gate. Default: `['mutation']`. */\n gatedOperations?: readonly GatedOperationType[];\n /** Override the user-facing error message shown when the flag is disabled. */\n userMessage?: string;\n}\n\n/** Actor/workspace fields the gate reads off the GraphQL context (either shape). */\ninterface GateContextShape {\n workspace?: { id?: string | null } | null;\n actor?: { id?: string | null; type?: string | null } | null;\n workspaceId?: string | null;\n actorId?: string | null;\n actorType?: string | null;\n}\n\nconst ACTOR_TYPES: readonly string[] = ['user', 'app', 'service', 'super_admin'];\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction isDocumentNode(value: unknown): value is DocumentNode {\n return isRecord(value) && Array.isArray((value as { definitions?: unknown }).definitions);\n}\n\n/** Find the operation that will actually execute for this request. */\nfunction findExecutedOperation(document: DocumentNode, operationName?: string | null): OperationDefinitionNode | null {\n const operations = document.definitions.filter(\n (definition): definition is OperationDefinitionNode => definition.kind === Kind.OPERATION_DEFINITION\n );\n\n if (operationName) {\n return operations.find((operation) => operation.name?.value === operationName) ?? null;\n }\n // Unnamed / single-operation request executes the first (only) operation.\n return operations[0] ?? null;\n}\n\nfunction coerceActorType(value: string | null | undefined): EvaluationContext['actorType'] {\n // Cast is sound: only reached after `ACTOR_TYPES.includes(value)` proves the\n // string is one of the known actor-type literals.\n return value && ACTOR_TYPES.includes(value) ? (value as EvaluationContext['actorType']) : undefined;\n}\n\n/**\n * Build the flag {@link EvaluationContext} from the GraphQL context, tolerating\n * both the nested (`workspace.id` / `actor.id`) and flat (`workspaceId` /\n * `actorId`) shapes. Returns `null` when no workspace can be resolved.\n */\nfunction resolveEvaluationContext(contextValue: unknown): EvaluationContext | null {\n // Cast to the fully-optional GateContextShape after the record guard; every\n // field is read defensively with optional chaining below.\n const ctx = (isRecord(contextValue) ? contextValue : {}) as GateContextShape;\n const workspaceId = ctx.workspace?.id ?? ctx.workspaceId ?? undefined;\n if (!workspaceId) {\n return null;\n }\n const actorId = ctx.actor?.id ?? ctx.actorId ?? undefined;\n const actorType = coerceActorType(ctx.actor?.type ?? ctx.actorType);\n return {\n workspaceId,\n ...(actorId ? { actorId } : {}),\n ...(actorType ? { actorType } : {}),\n };\n}\n\n/**\n * Create a GraphQL-Yoga/envelop plugin that gates operations behind a product\n * feature flag. Returns a {@link YogaPlugin} ready to drop into a service's\n * `yogaPlugins` array.\n */\nexport function createOperationsFlagGatePlugin(options: OperationsFlagGatePluginOptions): YogaPlugin {\n const { flagKey, productId } = options;\n const gatedOperations = new Set<string>(options.gatedOperations ?? ['mutation']);\n const userMessage = options.userMessage ?? 'This operation is currently unavailable.';\n\n let provider = options.provider ?? null;\n const getProvider = (): FeatureFlagProvider => {\n if (!provider) {\n provider = new FeatureFlagProvider({\n gatewayUrl:\n options.gatewayUrl ?? process.env['GLOBAL_PUBLIC_GATEWAY_URL'] ?? process.env['GLOBAL_INT_GATEWAY_URL'] ?? '',\n cacheTtlSeconds: options.cacheTtlSeconds ?? 60,\n defaultActorType: 'service',\n });\n }\n return provider;\n };\n\n return {\n async onExecute({\n args,\n }: {\n args: {\n document?: unknown;\n operationName?: string | null;\n variableValues?: Record<string, unknown>;\n contextValue?: unknown;\n };\n }): Promise<void> {\n if (!isDocumentNode(args.document)) {\n return;\n }\n\n const operation = findExecutedOperation(args.document, args.operationName);\n if (!operation || !gatedOperations.has(operation.operation)) {\n return; // Not a gated operation type — allow.\n }\n\n const evaluationContext = resolveEvaluationContext(args.contextValue);\n if (!evaluationContext) {\n // No workspace context to evaluate against → default-allow.\n logger.warn('[OperationsFlagGate] no workspace context — allowing operation', { flagKey, productId });\n return;\n }\n\n let enabled = true;\n try {\n enabled = await getProvider().isEnabled(flagKey, evaluationContext);\n } catch (error) {\n // Never let a flag-service failure block traffic (default-allow).\n logger.warn('[OperationsFlagGate] flag evaluation failed — allowing operation', {\n flagKey,\n productId,\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n\n if (!enabled) {\n logger.warn('[OperationsFlagGate] flag disabled — blocking operation', {\n flagKey,\n productId,\n workspaceId: evaluationContext.workspaceId,\n });\n throw new GraphQLError(userMessage, {\n extensions: {\n code: 'FEATURE_DISABLED',\n flagKey,\n productId,\n http: { status: 403 },\n },\n });\n }\n },\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { logger } from './chunk-CBZNP6RF.js';
1
+ import { logger } from './chunk-RU266375.js';
2
2
  import { __export, __name } from './chunk-XE4OXN2W.js';
3
3
  import { Elysia } from 'elysia';
4
4
 
@@ -241,5 +241,5 @@ __name(getMetricsForWindow, "getMetricsForWindow");
241
241
  logger.debug("[Metrics] Metrics middleware module loaded");
242
242
 
243
243
  export { MetricsCollector, createMetricsPlugin, getCurrentMetrics, getMetricsForWindow, metricsCollector, observability_exports };
244
- //# sourceMappingURL=chunk-5LXDPGDH.js.map
245
- //# sourceMappingURL=chunk-5LXDPGDH.js.map
244
+ //# sourceMappingURL=chunk-VAT66FJA.js.map
245
+ //# sourceMappingURL=chunk-VAT66FJA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/observability/index.ts","../src/observability/metrics.ts","../src/observability/elysia-middleware.ts"],"names":["MetricsCollector","instance","requests","MAX_REQUESTS","totalRequests","totalErrors","totalResponseTime","cleanupInterval","CLEANUP_INTERVAL_MS","DATA_RETENTION_MS","startCleanupTimer","getInstance","recordRequest","responseTimeMs","isError","metric","timestamp","Date","now","responseTime","push","length","shift","getMetrics","oneHourAgo","recentRequests","filter","r","avgResponseTime","reduce","sum","recentErrors","errorRate","Math","round","parseFloat","toFixed","requestsLastHour","errorsLastHour","getMetricsForWindow","windowMs","windowStart","windowRequests","windowErrors","reset","setInterval","cleanup","stopCleanupTimer","clearInterval","cutoff","initialLength","getStatistics","oldest","newest","bufferSize","oldestMetricAge","newestMetricAge","globalStats","metricsCollector","DEFAULT_CONFIG","slowRequestThreshold","enableDetailedLogging","createMetricsPlugin","config","finalConfig","Elysia","name","derive","requestStartTime","requestHasError","onRequest","request","store","metricsStore","url","URL","logger","debug","method","pathname","onError","error","errorMessage","Error","message","String","onAfterHandle","set","startTime","hasError","warn","statusCode","status","threshold","getCurrentMetrics"],"mappings":"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","file":"chunk-5LXDPGDH.js","sourcesContent":["/**\n * Observability Module\n *\n * Provides metrics collection and monitoring capabilities for Burdenoff products.\n * Uses Elysia plugins for request/response tracking.\n *\n * @module observability\n */\n\nexport { MetricsCollector, metricsCollector } from './metrics.js';\nexport type { Metrics } from './metrics.js';\n\nexport { createMetricsPlugin, getCurrentMetrics, getMetricsForWindow } from './elysia-middleware.js';\n","/**\n * Metrics Collection Module\n *\n * In-memory metrics collection for API monitoring and analytics.\n * This is a generalizable module for all Burdenoff products.\n *\n * Features:\n * - Request counting (total requests)\n * - Response time tracking (average response time)\n * - Error rate calculation (percentage of failed requests)\n * - Time-windowed metrics (last hour, last day, etc.)\n *\n * Architecture:\n * - Uses circular buffers to maintain recent metrics\n * - Automatically prunes old data to prevent memory leaks\n * - Thread-safe for concurrent request handling\n *\n * Future Enhancements:\n * - Replace with OpenTelemetry for distributed tracing\n * - Integrate Prometheus for metrics export\n * - Add per-endpoint metrics breakdown\n * - Persist metrics to ClickHouse for long-term storage\n *\n * @example\n * ```typescript\n * import { MetricsCollector } from '@burdenoff/be-sdk';\n *\n * const metrics = MetricsCollector.getInstance();\n *\n * // Record a successful request\n * metrics.recordRequest(150, false);\n *\n * // Record a failed request\n * metrics.recordRequest(50, true);\n *\n * // Get current metrics\n * const current = metrics.getMetrics();\n * console.log('Avg response time:', current.avgResponseTime);\n * console.log('Error rate:', current.errorRate);\n * ```\n */\n\ninterface RequestMetric {\n timestamp: number;\n responseTime: number;\n isError: boolean;\n}\n\nexport interface Metrics {\n avgResponseTime: number;\n errorRate: number;\n totalRequests: number;\n requestsLastHour: number;\n errorsLastHour: number;\n}\n\nexport class MetricsCollector {\n private static instance: MetricsCollector | null = null;\n\n // Circular buffer of recent requests (last 10,000 requests or 1 hour, whichever is smaller)\n private requests: RequestMetric[] = [];\n private readonly MAX_REQUESTS = 10000;\n\n // Global counters (since service start)\n private totalRequests = 0;\n private totalErrors = 0;\n private totalResponseTime = 0;\n\n // Cleanup interval\n private cleanupInterval: NodeJS.Timeout | null = null;\n private readonly CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n private readonly DATA_RETENTION_MS = 60 * 60 * 1000; // 1 hour\n\n private constructor() {\n // Private constructor for singleton\n this.startCleanupTimer();\n }\n\n /**\n * Get singleton instance\n */\n static getInstance(): MetricsCollector {\n if (!MetricsCollector.instance) {\n MetricsCollector.instance = new MetricsCollector();\n }\n return MetricsCollector.instance;\n }\n\n /**\n * Record a request metric\n *\n * @param responseTimeMs - Response time in milliseconds\n * @param isError - Whether the request resulted in an error\n */\n recordRequest(responseTimeMs: number, isError: boolean): void {\n const metric: RequestMetric = {\n timestamp: Date.now(),\n responseTime: responseTimeMs,\n isError,\n };\n\n // Add to circular buffer\n this.requests.push(metric);\n if (this.requests.length > this.MAX_REQUESTS) {\n this.requests.shift(); // Remove oldest\n }\n\n // Update global counters\n this.totalRequests++;\n this.totalResponseTime += responseTimeMs;\n if (isError) {\n this.totalErrors++;\n }\n }\n\n /**\n * Get current metrics\n *\n * Returns metrics for:\n * - All time (since service start)\n * - Last hour (recent activity)\n */\n getMetrics(): Metrics {\n const now = Date.now();\n const oneHourAgo = now - this.DATA_RETENTION_MS;\n\n // Filter requests from last hour\n const recentRequests = this.requests.filter((r) => r.timestamp >= oneHourAgo);\n\n // Calculate average response time (last hour)\n const avgResponseTime =\n recentRequests.length > 0\n ? recentRequests.reduce((sum, r) => sum + r.responseTime, 0) / recentRequests.length\n : 0;\n\n // Calculate error rate (last hour)\n const recentErrors = recentRequests.filter((r) => r.isError).length;\n const errorRate = recentRequests.length > 0 ? (recentErrors / recentRequests.length) * 100 : 0;\n\n return {\n avgResponseTime: Math.round(avgResponseTime), // Round to nearest ms\n errorRate: parseFloat(errorRate.toFixed(2)), // Round to 2 decimal places\n totalRequests: this.totalRequests,\n requestsLastHour: recentRequests.length,\n errorsLastHour: recentErrors,\n };\n }\n\n /**\n * Get metrics for a specific time window\n *\n * @param windowMs - Time window in milliseconds\n * @returns Metrics for the specified time window\n */\n getMetricsForWindow(windowMs: number): Metrics {\n const now = Date.now();\n const windowStart = now - windowMs;\n\n // Filter requests within window\n const windowRequests = this.requests.filter((r) => r.timestamp >= windowStart);\n\n // Calculate average response time\n const avgResponseTime =\n windowRequests.length > 0\n ? windowRequests.reduce((sum, r) => sum + r.responseTime, 0) / windowRequests.length\n : 0;\n\n // Calculate error rate\n const windowErrors = windowRequests.filter((r) => r.isError).length;\n const errorRate = windowRequests.length > 0 ? (windowErrors / windowRequests.length) * 100 : 0;\n\n return {\n avgResponseTime: Math.round(avgResponseTime),\n errorRate: parseFloat(errorRate.toFixed(2)),\n totalRequests: windowRequests.length,\n requestsLastHour: windowRequests.length,\n errorsLastHour: windowErrors,\n };\n }\n\n /**\n * Reset all metrics (useful for testing)\n */\n reset(): void {\n this.requests = [];\n this.totalRequests = 0;\n this.totalErrors = 0;\n this.totalResponseTime = 0;\n }\n\n /**\n * Start automatic cleanup timer\n * Removes metrics older than DATA_RETENTION_MS to prevent memory leaks\n */\n private startCleanupTimer(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanup();\n }, this.CLEANUP_INTERVAL_MS);\n }\n\n /**\n * Stop automatic cleanup timer (useful for testing or shutdown)\n */\n stopCleanupTimer(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /**\n * Remove metrics older than DATA_RETENTION_MS\n */\n private cleanup(): void {\n const now = Date.now();\n const cutoff = now - this.DATA_RETENTION_MS;\n const initialLength = this.requests.length;\n\n this.requests = this.requests.filter((r) => r.timestamp >= cutoff);\n\n const removedCount = initialLength - this.requests.length;\n if (removedCount > 0) {\n // Metrics cleaned up\n }\n }\n\n /**\n * Get detailed statistics (useful for debugging)\n */\n getStatistics(): {\n bufferSize: number;\n oldestMetricAge: number;\n newestMetricAge: number;\n globalStats: {\n totalRequests: number;\n totalErrors: number;\n avgResponseTime: number;\n errorRate: number;\n };\n } {\n const now = Date.now();\n const oldest = this.requests[0];\n const newest = this.requests[this.requests.length - 1];\n\n return {\n bufferSize: this.requests.length,\n oldestMetricAge: oldest ? now - oldest.timestamp : 0,\n newestMetricAge: newest ? now - newest.timestamp : 0,\n globalStats: {\n totalRequests: this.totalRequests,\n totalErrors: this.totalErrors,\n avgResponseTime: this.totalRequests > 0 ? Math.round(this.totalResponseTime / this.totalRequests) : 0,\n errorRate: this.totalRequests > 0 ? parseFloat(((this.totalErrors / this.totalRequests) * 100).toFixed(2)) : 0,\n },\n };\n }\n}\n\n// Export singleton instance\nexport const metricsCollector = MetricsCollector.getInstance();\n","/**\n * Elysia Metrics Middleware\n *\n * Elysia plugin for collecting request/response metrics.\n * This is a generalizable module for all Burdenoff products.\n *\n * What it tracks:\n * - Request count (total and per time window)\n * - Response time (average across all requests)\n * - Error rate (percentage of requests that failed)\n *\n * How it works:\n * - `onRequest` hook: Records request start time\n * - `onAfterHandle` hook: Calculates response time, records metrics\n * - `onError` hook: Marks request as error\n *\n * Integration:\n * Metrics are collected by MetricsCollector service and can be queried by:\n * - ActivityAnalyticsService (for analytics dashboard)\n * - Health check endpoints\n * - Monitoring tools (future: Prometheus exporter)\n *\n * @example\n * ```typescript\n * import { createMetricsPlugin } from '@burdenoff/be-sdk';\n *\n * const app = new Elysia()\n * .use(createMetricsPlugin({\n * slowRequestThreshold: 2000, // Log requests slower than 2s\n * enableDetailedLogging: true,\n * }));\n * ```\n */\n\nimport { Elysia, type AnyElysia } from 'elysia';\nimport { logger } from '../logger/index.js';\nimport type { MetricsMiddlewareConfig } from '../middleware/types.js';\nimport { metricsCollector } from './metrics.js';\n\n/**\n * Default configuration for metrics middleware\n */\nconst DEFAULT_CONFIG: Required<MetricsMiddlewareConfig> = {\n slowRequestThreshold: 1000, // 1 second\n enableDetailedLogging: false,\n};\n\n/**\n * Create Elysia metrics plugin\n *\n * Registers Elysia hooks to track request metrics:\n * - Response time\n * - Error rate\n * - Request count\n *\n * @param config - Configuration options\n * @returns Elysia plugin instance\n */\nexport function createMetricsPlugin(config?: MetricsMiddlewareConfig): AnyElysia {\n const finalConfig = { ...DEFAULT_CONFIG, ...config };\n\n return (\n new Elysia({ name: 'metrics' })\n // Store request start time and error status\n .derive(() => ({\n requestStartTime: 0,\n requestHasError: false,\n }))\n // Record request start time\n .onRequest(({ request, store }) => {\n const metricsStore = store as { requestStartTime: number; requestHasError: boolean };\n metricsStore.requestStartTime = Date.now();\n metricsStore.requestHasError = false;\n\n if (finalConfig.enableDetailedLogging) {\n const url = new URL(request.url);\n logger.debug('[Metrics] Request started', {\n method: request.method,\n url: url.pathname,\n });\n }\n })\n // Handle errors\n .onError(({ request, error, store }) => {\n const metricsStore = store as { requestHasError: boolean };\n metricsStore.requestHasError = true;\n\n const url = new URL(request.url);\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.debug('[Metrics] Request error', {\n method: request.method,\n url: url.pathname,\n error: errorMessage,\n });\n })\n // Record metrics after response\n .onAfterHandle(({ request, store, set }) => {\n const metricsStore = store as { requestStartTime: number; requestHasError: boolean };\n const startTime = metricsStore.requestStartTime;\n\n if (!startTime) {\n return;\n }\n\n const responseTime = Date.now() - startTime;\n const hasError = metricsStore.requestHasError || false;\n\n // Record metrics\n metricsCollector.recordRequest(responseTime, hasError);\n\n const url = new URL(request.url);\n\n // Log slow requests based on configured threshold\n if (responseTime > finalConfig.slowRequestThreshold) {\n logger.warn('[Metrics] Slow request detected', {\n method: request.method,\n url: url.pathname,\n responseTime: `${responseTime}ms`,\n statusCode: set.status || 200,\n threshold: `${finalConfig.slowRequestThreshold}ms`,\n });\n }\n\n if (finalConfig.enableDetailedLogging) {\n logger.debug('[Metrics] Request completed', {\n method: request.method,\n url: url.pathname,\n responseTime: `${responseTime}ms`,\n statusCode: set.status || 200,\n hasError,\n });\n }\n })\n );\n}\n\n/**\n * Get current metrics (utility function)\n */\nexport function getCurrentMetrics(): {\n avgResponseTime: number;\n errorRate: number;\n totalRequests: number;\n requestsLastHour: number;\n errorsLastHour: number;\n} {\n return metricsCollector.getMetrics();\n}\n\n/**\n * Get metrics for a specific time window (utility function)\n */\nexport function getMetricsForWindow(windowMs: number): {\n avgResponseTime: number;\n errorRate: number;\n totalRequests: number;\n requestsLastHour: number;\n errorsLastHour: number;\n} {\n return metricsCollector.getMetricsForWindow(windowMs);\n}\n\n// Log when metrics middleware is loaded\nlogger.debug('[Metrics] Metrics middleware module loaded');\n"]}
1
+ {"version":3,"sources":["../src/observability/index.ts","../src/observability/metrics.ts","../src/observability/elysia-middleware.ts"],"names":["MetricsCollector","instance","requests","MAX_REQUESTS","totalRequests","totalErrors","totalResponseTime","cleanupInterval","CLEANUP_INTERVAL_MS","DATA_RETENTION_MS","startCleanupTimer","getInstance","recordRequest","responseTimeMs","isError","metric","timestamp","Date","now","responseTime","push","length","shift","getMetrics","oneHourAgo","recentRequests","filter","r","avgResponseTime","reduce","sum","recentErrors","errorRate","Math","round","parseFloat","toFixed","requestsLastHour","errorsLastHour","getMetricsForWindow","windowMs","windowStart","windowRequests","windowErrors","reset","setInterval","cleanup","stopCleanupTimer","clearInterval","cutoff","initialLength","getStatistics","oldest","newest","bufferSize","oldestMetricAge","newestMetricAge","globalStats","metricsCollector","DEFAULT_CONFIG","slowRequestThreshold","enableDetailedLogging","createMetricsPlugin","config","finalConfig","Elysia","name","derive","requestStartTime","requestHasError","onRequest","request","store","metricsStore","url","URL","logger","debug","method","pathname","onError","error","errorMessage","Error","message","String","onAfterHandle","set","startTime","hasError","warn","statusCode","status","threshold","getCurrentMetrics"],"mappings":"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","file":"chunk-VAT66FJA.js","sourcesContent":["/**\n * Observability Module\n *\n * Provides metrics collection and monitoring capabilities for Burdenoff products.\n * Uses Elysia plugins for request/response tracking.\n *\n * @module observability\n */\n\nexport { MetricsCollector, metricsCollector } from './metrics.js';\nexport type { Metrics } from './metrics.js';\n\nexport { createMetricsPlugin, getCurrentMetrics, getMetricsForWindow } from './elysia-middleware.js';\n","/**\n * Metrics Collection Module\n *\n * In-memory metrics collection for API monitoring and analytics.\n * This is a generalizable module for all Burdenoff products.\n *\n * Features:\n * - Request counting (total requests)\n * - Response time tracking (average response time)\n * - Error rate calculation (percentage of failed requests)\n * - Time-windowed metrics (last hour, last day, etc.)\n *\n * Architecture:\n * - Uses circular buffers to maintain recent metrics\n * - Automatically prunes old data to prevent memory leaks\n * - Thread-safe for concurrent request handling\n *\n * Future Enhancements:\n * - Replace with OpenTelemetry for distributed tracing\n * - Integrate Prometheus for metrics export\n * - Add per-endpoint metrics breakdown\n * - Persist metrics to ClickHouse for long-term storage\n *\n * @example\n * ```typescript\n * import { MetricsCollector } from '@burdenoff/be-sdk';\n *\n * const metrics = MetricsCollector.getInstance();\n *\n * // Record a successful request\n * metrics.recordRequest(150, false);\n *\n * // Record a failed request\n * metrics.recordRequest(50, true);\n *\n * // Get current metrics\n * const current = metrics.getMetrics();\n * console.log('Avg response time:', current.avgResponseTime);\n * console.log('Error rate:', current.errorRate);\n * ```\n */\n\ninterface RequestMetric {\n timestamp: number;\n responseTime: number;\n isError: boolean;\n}\n\nexport interface Metrics {\n avgResponseTime: number;\n errorRate: number;\n totalRequests: number;\n requestsLastHour: number;\n errorsLastHour: number;\n}\n\nexport class MetricsCollector {\n private static instance: MetricsCollector | null = null;\n\n // Circular buffer of recent requests (last 10,000 requests or 1 hour, whichever is smaller)\n private requests: RequestMetric[] = [];\n private readonly MAX_REQUESTS = 10000;\n\n // Global counters (since service start)\n private totalRequests = 0;\n private totalErrors = 0;\n private totalResponseTime = 0;\n\n // Cleanup interval\n private cleanupInterval: NodeJS.Timeout | null = null;\n private readonly CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n private readonly DATA_RETENTION_MS = 60 * 60 * 1000; // 1 hour\n\n private constructor() {\n // Private constructor for singleton\n this.startCleanupTimer();\n }\n\n /**\n * Get singleton instance\n */\n static getInstance(): MetricsCollector {\n if (!MetricsCollector.instance) {\n MetricsCollector.instance = new MetricsCollector();\n }\n return MetricsCollector.instance;\n }\n\n /**\n * Record a request metric\n *\n * @param responseTimeMs - Response time in milliseconds\n * @param isError - Whether the request resulted in an error\n */\n recordRequest(responseTimeMs: number, isError: boolean): void {\n const metric: RequestMetric = {\n timestamp: Date.now(),\n responseTime: responseTimeMs,\n isError,\n };\n\n // Add to circular buffer\n this.requests.push(metric);\n if (this.requests.length > this.MAX_REQUESTS) {\n this.requests.shift(); // Remove oldest\n }\n\n // Update global counters\n this.totalRequests++;\n this.totalResponseTime += responseTimeMs;\n if (isError) {\n this.totalErrors++;\n }\n }\n\n /**\n * Get current metrics\n *\n * Returns metrics for:\n * - All time (since service start)\n * - Last hour (recent activity)\n */\n getMetrics(): Metrics {\n const now = Date.now();\n const oneHourAgo = now - this.DATA_RETENTION_MS;\n\n // Filter requests from last hour\n const recentRequests = this.requests.filter((r) => r.timestamp >= oneHourAgo);\n\n // Calculate average response time (last hour)\n const avgResponseTime =\n recentRequests.length > 0\n ? recentRequests.reduce((sum, r) => sum + r.responseTime, 0) / recentRequests.length\n : 0;\n\n // Calculate error rate (last hour)\n const recentErrors = recentRequests.filter((r) => r.isError).length;\n const errorRate = recentRequests.length > 0 ? (recentErrors / recentRequests.length) * 100 : 0;\n\n return {\n avgResponseTime: Math.round(avgResponseTime), // Round to nearest ms\n errorRate: parseFloat(errorRate.toFixed(2)), // Round to 2 decimal places\n totalRequests: this.totalRequests,\n requestsLastHour: recentRequests.length,\n errorsLastHour: recentErrors,\n };\n }\n\n /**\n * Get metrics for a specific time window\n *\n * @param windowMs - Time window in milliseconds\n * @returns Metrics for the specified time window\n */\n getMetricsForWindow(windowMs: number): Metrics {\n const now = Date.now();\n const windowStart = now - windowMs;\n\n // Filter requests within window\n const windowRequests = this.requests.filter((r) => r.timestamp >= windowStart);\n\n // Calculate average response time\n const avgResponseTime =\n windowRequests.length > 0\n ? windowRequests.reduce((sum, r) => sum + r.responseTime, 0) / windowRequests.length\n : 0;\n\n // Calculate error rate\n const windowErrors = windowRequests.filter((r) => r.isError).length;\n const errorRate = windowRequests.length > 0 ? (windowErrors / windowRequests.length) * 100 : 0;\n\n return {\n avgResponseTime: Math.round(avgResponseTime),\n errorRate: parseFloat(errorRate.toFixed(2)),\n totalRequests: windowRequests.length,\n requestsLastHour: windowRequests.length,\n errorsLastHour: windowErrors,\n };\n }\n\n /**\n * Reset all metrics (useful for testing)\n */\n reset(): void {\n this.requests = [];\n this.totalRequests = 0;\n this.totalErrors = 0;\n this.totalResponseTime = 0;\n }\n\n /**\n * Start automatic cleanup timer\n * Removes metrics older than DATA_RETENTION_MS to prevent memory leaks\n */\n private startCleanupTimer(): void {\n this.cleanupInterval = setInterval(() => {\n this.cleanup();\n }, this.CLEANUP_INTERVAL_MS);\n }\n\n /**\n * Stop automatic cleanup timer (useful for testing or shutdown)\n */\n stopCleanupTimer(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /**\n * Remove metrics older than DATA_RETENTION_MS\n */\n private cleanup(): void {\n const now = Date.now();\n const cutoff = now - this.DATA_RETENTION_MS;\n const initialLength = this.requests.length;\n\n this.requests = this.requests.filter((r) => r.timestamp >= cutoff);\n\n const removedCount = initialLength - this.requests.length;\n if (removedCount > 0) {\n // Metrics cleaned up\n }\n }\n\n /**\n * Get detailed statistics (useful for debugging)\n */\n getStatistics(): {\n bufferSize: number;\n oldestMetricAge: number;\n newestMetricAge: number;\n globalStats: {\n totalRequests: number;\n totalErrors: number;\n avgResponseTime: number;\n errorRate: number;\n };\n } {\n const now = Date.now();\n const oldest = this.requests[0];\n const newest = this.requests[this.requests.length - 1];\n\n return {\n bufferSize: this.requests.length,\n oldestMetricAge: oldest ? now - oldest.timestamp : 0,\n newestMetricAge: newest ? now - newest.timestamp : 0,\n globalStats: {\n totalRequests: this.totalRequests,\n totalErrors: this.totalErrors,\n avgResponseTime: this.totalRequests > 0 ? Math.round(this.totalResponseTime / this.totalRequests) : 0,\n errorRate: this.totalRequests > 0 ? parseFloat(((this.totalErrors / this.totalRequests) * 100).toFixed(2)) : 0,\n },\n };\n }\n}\n\n// Export singleton instance\nexport const metricsCollector = MetricsCollector.getInstance();\n","/**\n * Elysia Metrics Middleware\n *\n * Elysia plugin for collecting request/response metrics.\n * This is a generalizable module for all Burdenoff products.\n *\n * What it tracks:\n * - Request count (total and per time window)\n * - Response time (average across all requests)\n * - Error rate (percentage of requests that failed)\n *\n * How it works:\n * - `onRequest` hook: Records request start time\n * - `onAfterHandle` hook: Calculates response time, records metrics\n * - `onError` hook: Marks request as error\n *\n * Integration:\n * Metrics are collected by MetricsCollector service and can be queried by:\n * - ActivityAnalyticsService (for analytics dashboard)\n * - Health check endpoints\n * - Monitoring tools (future: Prometheus exporter)\n *\n * @example\n * ```typescript\n * import { createMetricsPlugin } from '@burdenoff/be-sdk';\n *\n * const app = new Elysia()\n * .use(createMetricsPlugin({\n * slowRequestThreshold: 2000, // Log requests slower than 2s\n * enableDetailedLogging: true,\n * }));\n * ```\n */\n\nimport { Elysia, type AnyElysia } from 'elysia';\nimport { logger } from '../logger/index.js';\nimport type { MetricsMiddlewareConfig } from '../middleware/types.js';\nimport { metricsCollector } from './metrics.js';\n\n/**\n * Default configuration for metrics middleware\n */\nconst DEFAULT_CONFIG: Required<MetricsMiddlewareConfig> = {\n slowRequestThreshold: 1000, // 1 second\n enableDetailedLogging: false,\n};\n\n/**\n * Create Elysia metrics plugin\n *\n * Registers Elysia hooks to track request metrics:\n * - Response time\n * - Error rate\n * - Request count\n *\n * @param config - Configuration options\n * @returns Elysia plugin instance\n */\nexport function createMetricsPlugin(config?: MetricsMiddlewareConfig): AnyElysia {\n const finalConfig = { ...DEFAULT_CONFIG, ...config };\n\n return (\n new Elysia({ name: 'metrics' })\n // Store request start time and error status\n .derive(() => ({\n requestStartTime: 0,\n requestHasError: false,\n }))\n // Record request start time\n .onRequest(({ request, store }) => {\n const metricsStore = store as { requestStartTime: number; requestHasError: boolean };\n metricsStore.requestStartTime = Date.now();\n metricsStore.requestHasError = false;\n\n if (finalConfig.enableDetailedLogging) {\n const url = new URL(request.url);\n logger.debug('[Metrics] Request started', {\n method: request.method,\n url: url.pathname,\n });\n }\n })\n // Handle errors\n .onError(({ request, error, store }) => {\n const metricsStore = store as { requestHasError: boolean };\n metricsStore.requestHasError = true;\n\n const url = new URL(request.url);\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.debug('[Metrics] Request error', {\n method: request.method,\n url: url.pathname,\n error: errorMessage,\n });\n })\n // Record metrics after response\n .onAfterHandle(({ request, store, set }) => {\n const metricsStore = store as { requestStartTime: number; requestHasError: boolean };\n const startTime = metricsStore.requestStartTime;\n\n if (!startTime) {\n return;\n }\n\n const responseTime = Date.now() - startTime;\n const hasError = metricsStore.requestHasError || false;\n\n // Record metrics\n metricsCollector.recordRequest(responseTime, hasError);\n\n const url = new URL(request.url);\n\n // Log slow requests based on configured threshold\n if (responseTime > finalConfig.slowRequestThreshold) {\n logger.warn('[Metrics] Slow request detected', {\n method: request.method,\n url: url.pathname,\n responseTime: `${responseTime}ms`,\n statusCode: set.status || 200,\n threshold: `${finalConfig.slowRequestThreshold}ms`,\n });\n }\n\n if (finalConfig.enableDetailedLogging) {\n logger.debug('[Metrics] Request completed', {\n method: request.method,\n url: url.pathname,\n responseTime: `${responseTime}ms`,\n statusCode: set.status || 200,\n hasError,\n });\n }\n })\n );\n}\n\n/**\n * Get current metrics (utility function)\n */\nexport function getCurrentMetrics(): {\n avgResponseTime: number;\n errorRate: number;\n totalRequests: number;\n requestsLastHour: number;\n errorsLastHour: number;\n} {\n return metricsCollector.getMetrics();\n}\n\n/**\n * Get metrics for a specific time window (utility function)\n */\nexport function getMetricsForWindow(windowMs: number): {\n avgResponseTime: number;\n errorRate: number;\n totalRequests: number;\n requestsLastHour: number;\n errorsLastHour: number;\n} {\n return metricsCollector.getMetricsForWindow(windowMs);\n}\n\n// Log when metrics middleware is loaded\nlogger.debug('[Metrics] Metrics middleware module loaded');\n"]}
@@ -1,7 +1,7 @@
1
- import { shouldSyncRelationship, shouldSyncEntity, parseRelationship, getCollectionForEntity, extractMinimalFields, extractEntityTitle, createRelationshipEvent, createEntityEvent, addGraphExtension, GraphRegistry, ensureServiceApplicationName } from './chunk-OCYZEBOL.js';
2
- import { getGraphEventEmitter, GraphEventEmitterImpl } from './chunk-URDYOM2L.js';
1
+ import { shouldSyncRelationship, shouldSyncEntity, parseRelationship, getCollectionForEntity, extractMinimalFields, extractEntityTitle, createRelationshipEvent, createEntityEvent, addGraphExtension, GraphRegistry, ensureServiceApplicationName } from './chunk-L5TDUAFN.js';
2
+ import { getGraphEventEmitter, GraphEventEmitterImpl } from './chunk-QJN4K7LD.js';
3
3
  import { ValidationError } from './chunk-QGBXVNRM.js';
4
- import { logger } from './chunk-CBZNP6RF.js';
4
+ import { logger } from './chunk-RU266375.js';
5
5
  import { __export, __name } from './chunk-XE4OXN2W.js';
6
6
 
7
7
  // src/graph/index.ts
@@ -44,10 +44,16 @@ function createPrismaGraphIntegration(options) {
44
44
  ensureServiceApplicationName(productName);
45
45
  const state = {
46
46
  graphEmitter: null,
47
+ basePrismaClient: null,
47
48
  extendedPrismaClient: null,
48
49
  emitterInitialized: false,
49
50
  initializationPromise: null
50
51
  };
52
+ function getOrCreateBasePrismaClient() {
53
+ state.basePrismaClient ??= createPrismaClient();
54
+ return state.basePrismaClient;
55
+ }
56
+ __name(getOrCreateBasePrismaClient, "getOrCreateBasePrismaClient");
51
57
  async function initializeGraphEmitter() {
52
58
  if (state.initializationPromise) {
53
59
  return state.initializationPromise;
@@ -68,7 +74,7 @@ function createPrismaGraphIntegration(options) {
68
74
  state.graphEmitter = new GraphEventEmitterImpl();
69
75
  logger.info(`[${serviceName}] Graph event emitter initialized`);
70
76
  state.emitterInitialized = true;
71
- const basePrisma = createPrismaClient();
77
+ const basePrisma = getOrCreateBasePrismaClient();
72
78
  state.extendedPrismaClient = initializeGraph(basePrisma, graphConfig, {
73
79
  productName,
74
80
  eventEmitter: state.graphEmitter,
@@ -92,7 +98,7 @@ function createPrismaGraphIntegration(options) {
92
98
  void initializeGraphEmitter();
93
99
  }
94
100
  if (!process.env["GRAPH_EVENTS_ENABLED"] || process.env["GRAPH_EVENTS_ENABLED"] !== "true" || !state.extendedPrismaClient) {
95
- const baseClient = createPrismaClient();
101
+ const baseClient = getOrCreateBasePrismaClient();
96
102
  return {
97
103
  client: baseClient
98
104
  };
@@ -117,11 +123,13 @@ function createPrismaGraphIntegration(options) {
117
123
  await state.graphEmitter.disconnect();
118
124
  logger.info(`[${serviceName}] Graph event emitter disconnected`);
119
125
  }
120
- if (state.extendedPrismaClient) {
121
- await state.extendedPrismaClient.$disconnect();
122
- state.extendedPrismaClient = null;
126
+ const clientToDisconnect = state.extendedPrismaClient ?? state.basePrismaClient;
127
+ if (clientToDisconnect) {
128
+ await clientToDisconnect.$disconnect();
123
129
  logger.info(`[${serviceName}] Prisma client disconnected`);
124
130
  }
131
+ state.extendedPrismaClient = null;
132
+ state.basePrismaClient = null;
125
133
  state.emitterInitialized = false;
126
134
  }
127
135
  __name(cleanup, "cleanup");
@@ -1874,5 +1882,5 @@ var GraphModule = class {
1874
1882
  };
1875
1883
 
1876
1884
  export { AUDIT_FIELDS, GraphEventsPublisher, GraphExportService, GraphModule, SOFT_DELETE_FIELDS, STANDARD_FIELDS, TENANT_FIELDS, createGraphEventsHelper, createGraphExportService, createPrismaGraphIntegration, createRelationshipFromEntity, defineEntity, defineGraphConfig, defineModuleGraph, defineRelationship, getGraphEventsPublisher, getGraphStats, graph_exports, initializeGraph, isGraphInitialized };
1877
- //# sourceMappingURL=chunk-7E76FL2C.js.map
1878
- //# sourceMappingURL=chunk-7E76FL2C.js.map
1885
+ //# sourceMappingURL=chunk-XCQN6GH7.js.map
1886
+ //# sourceMappingURL=chunk-XCQN6GH7.js.map