nucleus-core-ts 0.10.111 → 0.10.113
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.
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ and limitations under the License.
|
|
|
15
15
|
***************************************************************************** */var Reflect2;(function(Reflect3){(function(factory){var root=typeof globalThis==="object"?globalThis:typeof global==="object"?global:typeof self==="object"?self:typeof this==="object"?this:sloppyModeThis(),exporter=makeExporter(Reflect3);if(typeof root.Reflect<"u")exporter=makeExporter(root.Reflect,exporter);if(factory(exporter,root),typeof root.Reflect>"u")root.Reflect=Reflect3;function makeExporter(target,previous){return function(key,value){if(Object.defineProperty(target,key,{configurable:!0,writable:!0,value}),previous)previous(key,value)}}function functionThis(){try{return Function("return this;")()}catch(_){}}function indirectEvalThis(){try{return(0,eval)("(function() { return this; })()")}catch(_){}}function sloppyModeThis(){return functionThis()||indirectEvalThis()}})(function(exporter,root){var hasOwn=Object.prototype.hasOwnProperty,supportsSymbol=typeof Symbol==="function",toPrimitiveSymbol=supportsSymbol&&typeof Symbol.toPrimitive<"u"?Symbol.toPrimitive:"@@toPrimitive",iteratorSymbol=supportsSymbol&&typeof Symbol.iterator<"u"?Symbol.iterator:"@@iterator",supportsCreate=typeof Object.create==="function",supportsProto={__proto__:[]}instanceof Array,downLevel=!supportsCreate&&!supportsProto,HashMap={create:supportsCreate?function(){return MakeDictionary(Object.create(null))}:supportsProto?function(){return MakeDictionary({__proto__:null})}:function(){return MakeDictionary({})},has:downLevel?function(map,key){return hasOwn.call(map,key)}:function(map,key){return key in map},get:downLevel?function(map,key){return hasOwn.call(map,key)?map[key]:void 0}:function(map,key){return map[key]}},functionPrototype=Object.getPrototypeOf(Function),_Map=typeof Map==="function"&&typeof Map.prototype.entries==="function"?Map:CreateMapPolyfill(),_Set=typeof Set==="function"&&typeof Set.prototype.entries==="function"?Set:CreateSetPolyfill(),_WeakMap=typeof WeakMap==="function"?WeakMap:CreateWeakMapPolyfill(),registrySymbol=supportsSymbol?Symbol.for("@reflect-metadata:registry"):void 0,metadataRegistry=GetOrCreateMetadataRegistry(),metadataProvider=CreateMetadataProvider(metadataRegistry);function decorate(decorators,target,propertyKey,attributes){if(!IsUndefined(propertyKey)){if(!IsArray(decorators))throw TypeError();if(!IsObject(target))throw TypeError();if(!IsObject(attributes)&&!IsUndefined(attributes)&&!IsNull(attributes))throw TypeError();if(IsNull(attributes))attributes=void 0;return propertyKey=ToPropertyKey(propertyKey),DecorateProperty(decorators,target,propertyKey,attributes)}else{if(!IsArray(decorators))throw TypeError();if(!IsConstructor(target))throw TypeError();return DecorateConstructor(decorators,target)}}exporter("decorate",decorate);function metadata(metadataKey,metadataValue){function decorator(target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey)&&!IsPropertyKey(propertyKey))throw TypeError();OrdinaryDefineOwnMetadata(metadataKey,metadataValue,target,propertyKey)}return decorator}exporter("metadata",metadata);function defineMetadata(metadataKey,metadataValue,target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);return OrdinaryDefineOwnMetadata(metadataKey,metadataValue,target,propertyKey)}exporter("defineMetadata",defineMetadata);function hasMetadata(metadataKey,target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);return OrdinaryHasMetadata(metadataKey,target,propertyKey)}exporter("hasMetadata",hasMetadata);function hasOwnMetadata(metadataKey,target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);return OrdinaryHasOwnMetadata(metadataKey,target,propertyKey)}exporter("hasOwnMetadata",hasOwnMetadata);function getMetadata(metadataKey,target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);return OrdinaryGetMetadata(metadataKey,target,propertyKey)}exporter("getMetadata",getMetadata);function getOwnMetadata(metadataKey,target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);return OrdinaryGetOwnMetadata(metadataKey,target,propertyKey)}exporter("getOwnMetadata",getOwnMetadata);function getMetadataKeys(target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);return OrdinaryMetadataKeys(target,propertyKey)}exporter("getMetadataKeys",getMetadataKeys);function getOwnMetadataKeys(target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);return OrdinaryOwnMetadataKeys(target,propertyKey)}exporter("getOwnMetadataKeys",getOwnMetadataKeys);function deleteMetadata(metadataKey,target,propertyKey){if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);if(!IsObject(target))throw TypeError();if(!IsUndefined(propertyKey))propertyKey=ToPropertyKey(propertyKey);var provider=GetMetadataProvider(target,propertyKey,!1);if(IsUndefined(provider))return!1;return provider.OrdinaryDeleteMetadata(metadataKey,target,propertyKey)}exporter("deleteMetadata",deleteMetadata);function DecorateConstructor(decorators,target){for(var i=decorators.length-1;i>=0;--i){var decorator=decorators[i],decorated=decorator(target);if(!IsUndefined(decorated)&&!IsNull(decorated)){if(!IsConstructor(decorated))throw TypeError();target=decorated}}return target}function DecorateProperty(decorators,target,propertyKey,descriptor){for(var i=decorators.length-1;i>=0;--i){var decorator=decorators[i],decorated=decorator(target,propertyKey,descriptor);if(!IsUndefined(decorated)&&!IsNull(decorated)){if(!IsObject(decorated))throw TypeError();descriptor=decorated}}return descriptor}function OrdinaryHasMetadata(MetadataKey,O,P){var hasOwn2=OrdinaryHasOwnMetadata(MetadataKey,O,P);if(hasOwn2)return!0;var parent=OrdinaryGetPrototypeOf(O);if(!IsNull(parent))return OrdinaryHasMetadata(MetadataKey,parent,P);return!1}function OrdinaryHasOwnMetadata(MetadataKey,O,P){var provider=GetMetadataProvider(O,P,!1);if(IsUndefined(provider))return!1;return ToBoolean(provider.OrdinaryHasOwnMetadata(MetadataKey,O,P))}function OrdinaryGetMetadata(MetadataKey,O,P){var hasOwn2=OrdinaryHasOwnMetadata(MetadataKey,O,P);if(hasOwn2)return OrdinaryGetOwnMetadata(MetadataKey,O,P);var parent=OrdinaryGetPrototypeOf(O);if(!IsNull(parent))return OrdinaryGetMetadata(MetadataKey,parent,P);return}function OrdinaryGetOwnMetadata(MetadataKey,O,P){var provider=GetMetadataProvider(O,P,!1);if(IsUndefined(provider))return;return provider.OrdinaryGetOwnMetadata(MetadataKey,O,P)}function OrdinaryDefineOwnMetadata(MetadataKey,MetadataValue,O,P){var provider=GetMetadataProvider(O,P,!0);provider.OrdinaryDefineOwnMetadata(MetadataKey,MetadataValue,O,P)}function OrdinaryMetadataKeys(O,P){var ownKeys=OrdinaryOwnMetadataKeys(O,P),parent=OrdinaryGetPrototypeOf(O);if(parent===null)return ownKeys;var parentKeys=OrdinaryMetadataKeys(parent,P);if(parentKeys.length<=0)return ownKeys;if(ownKeys.length<=0)return parentKeys;var set=new _Set,keys=[];for(var _i=0,ownKeys_1=ownKeys;_i<ownKeys_1.length;_i++){var key=ownKeys_1[_i],hasKey=set.has(key);if(!hasKey)set.add(key),keys.push(key)}for(var _a=0,parentKeys_1=parentKeys;_a<parentKeys_1.length;_a++){var key=parentKeys_1[_a],hasKey=set.has(key);if(!hasKey)set.add(key),keys.push(key)}return keys}function OrdinaryOwnMetadataKeys(O,P){var provider=GetMetadataProvider(O,P,!1);if(!provider)return[];return provider.OrdinaryOwnMetadataKeys(O,P)}function Type(x){if(x===null)return 1;switch(typeof x){case"undefined":return 0;case"boolean":return 2;case"string":return 3;case"symbol":return 4;case"number":return 5;case"object":return x===null?1:6;default:return 6}}function IsUndefined(x){return x===void 0}function IsNull(x){return x===null}function IsSymbol(x){return typeof x==="symbol"}function IsObject(x){return typeof x==="object"?x!==null:typeof x==="function"}function ToPrimitive(input,PreferredType){switch(Type(input)){case 0:return input;case 1:return input;case 2:return input;case 3:return input;case 4:return input;case 5:return input}var hint=PreferredType===3?"string":PreferredType===5?"number":"default",exoticToPrim=GetMethod(input,toPrimitiveSymbol);if(exoticToPrim!==void 0){var result=exoticToPrim.call(input,hint);if(IsObject(result))throw TypeError();return result}return OrdinaryToPrimitive(input,hint==="default"?"number":hint)}function OrdinaryToPrimitive(O,hint){if(hint==="string"){var toString_1=O.toString;if(IsCallable(toString_1)){var result=toString_1.call(O);if(!IsObject(result))return result}var valueOf=O.valueOf;if(IsCallable(valueOf)){var result=valueOf.call(O);if(!IsObject(result))return result}}else{var valueOf=O.valueOf;if(IsCallable(valueOf)){var result=valueOf.call(O);if(!IsObject(result))return result}var toString_2=O.toString;if(IsCallable(toString_2)){var result=toString_2.call(O);if(!IsObject(result))return result}}throw TypeError()}function ToBoolean(argument){return!!argument}function ToString(argument){return""+argument}function ToPropertyKey(argument){var key=ToPrimitive(argument,3);if(IsSymbol(key))return key;return ToString(key)}function IsArray(argument){return Array.isArray?Array.isArray(argument):argument instanceof Object?argument instanceof Array:Object.prototype.toString.call(argument)==="[object Array]"}function IsCallable(argument){return typeof argument==="function"}function IsConstructor(argument){return typeof argument==="function"}function IsPropertyKey(argument){switch(Type(argument)){case 3:return!0;case 4:return!0;default:return!1}}function SameValueZero(x,y){return x===y||x!==x&&y!==y}function GetMethod(V,P){var func=V[P];if(func===void 0||func===null)return;if(!IsCallable(func))throw TypeError();return func}function GetIterator(obj){var method=GetMethod(obj,iteratorSymbol);if(!IsCallable(method))throw TypeError();var iterator=method.call(obj);if(!IsObject(iterator))throw TypeError();return iterator}function IteratorValue(iterResult){return iterResult.value}function IteratorStep(iterator){var result=iterator.next();return result.done?!1:result}function IteratorClose(iterator){var f=iterator.return;if(f)f.call(iterator)}function OrdinaryGetPrototypeOf(O){var proto=Object.getPrototypeOf(O);if(typeof O!=="function"||O===functionPrototype)return proto;if(proto!==functionPrototype)return proto;var prototype=O.prototype,prototypeProto=prototype&&Object.getPrototypeOf(prototype);if(prototypeProto==null||prototypeProto===Object.prototype)return proto;var constructor=prototypeProto.constructor;if(typeof constructor!=="function")return proto;if(constructor===O)return proto;return constructor}function CreateMetadataRegistry(){var fallback;if(!IsUndefined(registrySymbol)&&typeof root.Reflect<"u"&&!(registrySymbol in root.Reflect)&&typeof root.Reflect.defineMetadata==="function")fallback=CreateFallbackProvider(root.Reflect);var first,second,rest,targetProviderMap=new _WeakMap,registry={registerProvider,getProvider,setProvider};return registry;function registerProvider(provider){if(!Object.isExtensible(registry))throw Error("Cannot add provider to a frozen registry.");switch(!0){case fallback===provider:break;case IsUndefined(first):first=provider;break;case first===provider:break;case IsUndefined(second):second=provider;break;case second===provider:break;default:if(rest===void 0)rest=new _Set;rest.add(provider);break}}function getProviderNoCache(O,P){if(!IsUndefined(first)){if(first.isProviderFor(O,P))return first;if(!IsUndefined(second)){if(second.isProviderFor(O,P))return first;if(!IsUndefined(rest)){var iterator=GetIterator(rest);while(!0){var next=IteratorStep(iterator);if(!next)return;var provider=IteratorValue(next);if(provider.isProviderFor(O,P))return IteratorClose(iterator),provider}}}}if(!IsUndefined(fallback)&&fallback.isProviderFor(O,P))return fallback;return}function getProvider(O,P){var providerMap=targetProviderMap.get(O),provider;if(!IsUndefined(providerMap))provider=providerMap.get(P);if(!IsUndefined(provider))return provider;if(provider=getProviderNoCache(O,P),!IsUndefined(provider)){if(IsUndefined(providerMap))providerMap=new _Map,targetProviderMap.set(O,providerMap);providerMap.set(P,provider)}return provider}function hasProvider(provider){if(IsUndefined(provider))throw TypeError();return first===provider||second===provider||!IsUndefined(rest)&&rest.has(provider)}function setProvider(O,P,provider){if(!hasProvider(provider))throw Error("Metadata provider not registered.");var existingProvider=getProvider(O,P);if(existingProvider!==provider){if(!IsUndefined(existingProvider))return!1;var providerMap=targetProviderMap.get(O);if(IsUndefined(providerMap))providerMap=new _Map,targetProviderMap.set(O,providerMap);providerMap.set(P,provider)}return!0}}function GetOrCreateMetadataRegistry(){var metadataRegistry2;if(!IsUndefined(registrySymbol)&&IsObject(root.Reflect)&&Object.isExtensible(root.Reflect))metadataRegistry2=root.Reflect[registrySymbol];if(IsUndefined(metadataRegistry2))metadataRegistry2=CreateMetadataRegistry();if(!IsUndefined(registrySymbol)&&IsObject(root.Reflect)&&Object.isExtensible(root.Reflect))Object.defineProperty(root.Reflect,registrySymbol,{enumerable:!1,configurable:!1,writable:!1,value:metadataRegistry2});return metadataRegistry2}function CreateMetadataProvider(registry){var metadata2=new _WeakMap,provider={isProviderFor:function(O,P){var targetMetadata=metadata2.get(O);if(IsUndefined(targetMetadata))return!1;return targetMetadata.has(P)},OrdinaryDefineOwnMetadata:OrdinaryDefineOwnMetadata2,OrdinaryHasOwnMetadata:OrdinaryHasOwnMetadata2,OrdinaryGetOwnMetadata:OrdinaryGetOwnMetadata2,OrdinaryOwnMetadataKeys:OrdinaryOwnMetadataKeys2,OrdinaryDeleteMetadata};return metadataRegistry.registerProvider(provider),provider;function GetOrCreateMetadataMap(O,P,Create){var targetMetadata=metadata2.get(O),createdTargetMetadata=!1;if(IsUndefined(targetMetadata)){if(!Create)return;targetMetadata=new _Map,metadata2.set(O,targetMetadata),createdTargetMetadata=!0}var metadataMap=targetMetadata.get(P);if(IsUndefined(metadataMap)){if(!Create)return;if(metadataMap=new _Map,targetMetadata.set(P,metadataMap),!registry.setProvider(O,P,provider)){if(targetMetadata.delete(P),createdTargetMetadata)metadata2.delete(O);throw Error("Wrong provider for target.")}}return metadataMap}function OrdinaryHasOwnMetadata2(MetadataKey,O,P){var metadataMap=GetOrCreateMetadataMap(O,P,!1);if(IsUndefined(metadataMap))return!1;return ToBoolean(metadataMap.has(MetadataKey))}function OrdinaryGetOwnMetadata2(MetadataKey,O,P){var metadataMap=GetOrCreateMetadataMap(O,P,!1);if(IsUndefined(metadataMap))return;return metadataMap.get(MetadataKey)}function OrdinaryDefineOwnMetadata2(MetadataKey,MetadataValue,O,P){var metadataMap=GetOrCreateMetadataMap(O,P,!0);metadataMap.set(MetadataKey,MetadataValue)}function OrdinaryOwnMetadataKeys2(O,P){var keys=[],metadataMap=GetOrCreateMetadataMap(O,P,!1);if(IsUndefined(metadataMap))return keys;var keysObj=metadataMap.keys(),iterator=GetIterator(keysObj),k=0;while(!0){var next=IteratorStep(iterator);if(!next)return keys.length=k,keys;var nextValue=IteratorValue(next);try{keys[k]=nextValue}catch(e){try{IteratorClose(iterator)}finally{throw e}}k++}}function OrdinaryDeleteMetadata(MetadataKey,O,P){var metadataMap=GetOrCreateMetadataMap(O,P,!1);if(IsUndefined(metadataMap))return!1;if(!metadataMap.delete(MetadataKey))return!1;if(metadataMap.size===0){var targetMetadata=metadata2.get(O);if(!IsUndefined(targetMetadata)){if(targetMetadata.delete(P),targetMetadata.size===0)metadata2.delete(targetMetadata)}}return!0}}function CreateFallbackProvider(reflect){var{defineMetadata:defineMetadata2,hasOwnMetadata:hasOwnMetadata2,getOwnMetadata:getOwnMetadata2,getOwnMetadataKeys:getOwnMetadataKeys2,deleteMetadata:deleteMetadata2}=reflect,metadataOwner=new _WeakMap,provider={isProviderFor:function(O,P){var metadataPropertySet=metadataOwner.get(O);if(!IsUndefined(metadataPropertySet)&&metadataPropertySet.has(P))return!0;if(getOwnMetadataKeys2(O,P).length){if(IsUndefined(metadataPropertySet))metadataPropertySet=new _Set,metadataOwner.set(O,metadataPropertySet);return metadataPropertySet.add(P),!0}return!1},OrdinaryDefineOwnMetadata:defineMetadata2,OrdinaryHasOwnMetadata:hasOwnMetadata2,OrdinaryGetOwnMetadata:getOwnMetadata2,OrdinaryOwnMetadataKeys:getOwnMetadataKeys2,OrdinaryDeleteMetadata:deleteMetadata2};return provider}function GetMetadataProvider(O,P,Create){var registeredProvider=metadataRegistry.getProvider(O,P);if(!IsUndefined(registeredProvider))return registeredProvider;if(Create){if(metadataRegistry.setProvider(O,P,metadataProvider))return metadataProvider;throw Error("Illegal state.")}return}function CreateMapPolyfill(){var cacheSentinel={},arraySentinel=[],MapIterator=function(){function MapIterator2(keys,values,selector){this._index=0,this._keys=keys,this._values=values,this._selector=selector}return MapIterator2.prototype["@@iterator"]=function(){return this},MapIterator2.prototype[iteratorSymbol]=function(){return this},MapIterator2.prototype.next=function(){var index=this._index;if(index>=0&&index<this._keys.length){var result=this._selector(this._keys[index],this._values[index]);if(index+1>=this._keys.length)this._index=-1,this._keys=arraySentinel,this._values=arraySentinel;else this._index++;return{value:result,done:!1}}return{value:void 0,done:!0}},MapIterator2.prototype.throw=function(error){if(this._index>=0)this._index=-1,this._keys=arraySentinel,this._values=arraySentinel;throw error},MapIterator2.prototype.return=function(value){if(this._index>=0)this._index=-1,this._keys=arraySentinel,this._values=arraySentinel;return{value,done:!0}},MapIterator2}(),Map2=function(){function Map3(){this._keys=[],this._values=[],this._cacheKey=cacheSentinel,this._cacheIndex=-2}return Object.defineProperty(Map3.prototype,"size",{get:function(){return this._keys.length},enumerable:!0,configurable:!0}),Map3.prototype.has=function(key){return this._find(key,!1)>=0},Map3.prototype.get=function(key){var index=this._find(key,!1);return index>=0?this._values[index]:void 0},Map3.prototype.set=function(key,value){var index=this._find(key,!0);return this._values[index]=value,this},Map3.prototype.delete=function(key){var index=this._find(key,!1);if(index>=0){var size=this._keys.length;for(var i=index+1;i<size;i++)this._keys[i-1]=this._keys[i],this._values[i-1]=this._values[i];if(this._keys.length--,this._values.length--,SameValueZero(key,this._cacheKey))this._cacheKey=cacheSentinel,this._cacheIndex=-2;return!0}return!1},Map3.prototype.clear=function(){this._keys.length=0,this._values.length=0,this._cacheKey=cacheSentinel,this._cacheIndex=-2},Map3.prototype.keys=function(){return new MapIterator(this._keys,this._values,getKey)},Map3.prototype.values=function(){return new MapIterator(this._keys,this._values,getValue)},Map3.prototype.entries=function(){return new MapIterator(this._keys,this._values,getEntry)},Map3.prototype["@@iterator"]=function(){return this.entries()},Map3.prototype[iteratorSymbol]=function(){return this.entries()},Map3.prototype._find=function(key,insert){if(!SameValueZero(this._cacheKey,key)){this._cacheIndex=-1;for(var i=0;i<this._keys.length;i++)if(SameValueZero(this._keys[i],key)){this._cacheIndex=i;break}}if(this._cacheIndex<0&&insert)this._cacheIndex=this._keys.length,this._keys.push(key),this._values.push(void 0);return this._cacheIndex},Map3}();return Map2;function getKey(key,_){return key}function getValue(_,value){return value}function getEntry(key,value){return[key,value]}}function CreateSetPolyfill(){var Set2=function(){function Set3(){this._map=new _Map}return Object.defineProperty(Set3.prototype,"size",{get:function(){return this._map.size},enumerable:!0,configurable:!0}),Set3.prototype.has=function(value){return this._map.has(value)},Set3.prototype.add=function(value){return this._map.set(value,value),this},Set3.prototype.delete=function(value){return this._map.delete(value)},Set3.prototype.clear=function(){this._map.clear()},Set3.prototype.keys=function(){return this._map.keys()},Set3.prototype.values=function(){return this._map.keys()},Set3.prototype.entries=function(){return this._map.entries()},Set3.prototype["@@iterator"]=function(){return this.keys()},Set3.prototype[iteratorSymbol]=function(){return this.keys()},Set3}();return Set2}function CreateWeakMapPolyfill(){var UUID_SIZE=16,keys=HashMap.create(),rootKey=CreateUniqueKey();return function(){function WeakMap2(){this._key=CreateUniqueKey()}return WeakMap2.prototype.has=function(target){var table=GetOrCreateWeakMapTable(target,!1);return table!==void 0?HashMap.has(table,this._key):!1},WeakMap2.prototype.get=function(target){var table=GetOrCreateWeakMapTable(target,!1);return table!==void 0?HashMap.get(table,this._key):void 0},WeakMap2.prototype.set=function(target,value){var table=GetOrCreateWeakMapTable(target,!0);return table[this._key]=value,this},WeakMap2.prototype.delete=function(target){var table=GetOrCreateWeakMapTable(target,!1);return table!==void 0?delete table[this._key]:!1},WeakMap2.prototype.clear=function(){this._key=CreateUniqueKey()},WeakMap2}();function CreateUniqueKey(){var key;do key="@@WeakMap@@"+CreateUUID();while(HashMap.has(keys,key));return keys[key]=!0,key}function GetOrCreateWeakMapTable(target,create){if(!hasOwn.call(target,rootKey)){if(!create)return;Object.defineProperty(target,rootKey,{value:HashMap.create()})}return target[rootKey]}function FillRandomBytes(buffer,size){for(var i=0;i<size;++i)buffer[i]=Math.random()*255|0;return buffer}function GenRandomBytes(size){if(typeof Uint8Array==="function"){var array=new Uint8Array(size);if(typeof crypto<"u")crypto.getRandomValues(array);else if(typeof msCrypto<"u")msCrypto.getRandomValues(array);else FillRandomBytes(array,size);return array}return FillRandomBytes(Array(size),size)}function CreateUUID(){var data=GenRandomBytes(UUID_SIZE);data[6]=data[6]&79|64,data[8]=data[8]&191|128;var result="";for(var offset=0;offset<UUID_SIZE;++offset){var byte=data[offset];if(offset===4||offset===6||offset===8)result+="-";if(byte<16)result+="0";result+=byte.toString(16).toLowerCase()}return result}}function MakeDictionary(obj){return obj.__=void 0,delete obj.__,obj}})})(Reflect2||(Reflect2={}))});function randomId(){let webCrypto=globalThis.crypto;if(typeof webCrypto?.randomUUID==="function")return webCrypto.randomUUID();if(typeof webCrypto?.getRandomValues==="function"){let bytes=webCrypto.getRandomValues(new Uint8Array(16));bytes[6]=(bytes[6]??0)&15|64,bytes[8]=(bytes[8]??0)&63|128;let hex=Array.from(bytes,(b)=>b.toString(16).padStart(2,"0")).join("");return`${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`}return`id-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function severityRank(severity){return AUDIT_SEVERITY_RANK[severity??"info"]??0}function classifyAudit(operation,summary){let op=(operation||"").toUpperCase();if(summary?.startsWith("API key rejected"))return{severity:"medium",category:"auth"};if(summary&&AUTH_FAILURE_CLASSIFICATION[summary])return AUTH_FAILURE_CLASSIFICATION[summary];if(op.startsWith("IMPERSONATE")||op==="HARD_DELETE"||op==="CHANGE_USER_ID"||op==="PROVISION"||op==="RESTORE"||op.startsWith("ADMIN_"))return{severity:"high",category:"admin"};if(op.endsWith("_FAILED"))return{severity:"medium",category:"auth"};if(op.startsWith("PASSWORD"))return{severity:"medium",category:"auth"};if(op==="LOGIN"||op==="LOGOUT"||op==="REGISTER"||op==="OAUTH_LOGIN"||op==="MAGIC_LINK"||op==="INVITE")return{severity:"info",category:"auth"};if(op==="CREATE"||op==="UPDATE"||op==="PATCH"||op==="DELETE"||op==="TOGGLE"||op==="VERIFICATION")return{severity:"info",category:"data_change"};if(op==="GET"||op==="POST"||op==="PUT"||op==="PATCH"||op==="HEAD")return{severity:"low",category:"auth"};return{severity:"info",category:"data_change"}}var AUDIT_SEVERITY_RANK,ROUTINE_AUTH_REASONS,DEFAULT_AUDIT_SUPPRESS_REASONS,AUTH_FAILURE_CLASSIFICATION;var init_auditTaxonomy=__esm(()=>{AUDIT_SEVERITY_RANK={info:0,low:1,medium:2,high:3,critical:4};ROUTINE_AUTH_REASONS=["No session token","Invalid session","Session expired","Session inactive timeout","Authentication secrets not defined"],DEFAULT_AUDIT_SUPPRESS_REASONS=[...ROUTINE_AUTH_REASONS],AUTH_FAILURE_CLASSIFICATION={"No session token":{severity:"low",category:"auth"},"Invalid session":{severity:"low",category:"auth"},"Session expired":{severity:"low",category:"auth"},"Session inactive timeout":{severity:"low",category:"auth"},"Authentication secrets not defined":{severity:"critical",category:"config"},"Session revoked":{severity:"high",category:"security_anomaly"},"Invalid or missing access token":{severity:"medium",category:"auth"},"Access token tenant binding failed":{severity:"high",category:"security_anomaly"},"Invalid API key":{severity:"medium",category:"auth"},"Cohort expired":{severity:"medium",category:"authz"}}});var AUTH_LOGIN="authentication.login",AUTH_REGISTER="authentication.register",AUTH_SESSION="authentication.session",AUTH_PASSWORD_CHANGE="authentication.passwordChange",AUTH_PASSWORD_RESET="authentication.passwordReset",AUTH_PASSWORD_SET="authentication.passwordSet",TENANT_PROVISION="tenant.provision",TENANT_SELF_SIGNUP="tenant.selfSignup",TENANT_SUSPEND="tenant.suspend",matchesScope=(scope,enabledScopes)=>{if(enabledScopes.length===0)return!1;if(enabledScopes.includes("*"))return!0;if(enabledScopes.includes(scope))return!0;let category=scope.split(".")[0];if(category&&enabledScopes.includes(`${category}.*`))return!0;return!1};var init_scopes=()=>{};var LOG_LEVEL_PRIORITY,LOG_LEVEL_COLORS,RESET_COLOR="\x1B[0m",DIM_COLOR="\x1B[2m",BOLD_COLOR="\x1B[1m";var init_types=__esm(()=>{LOG_LEVEL_PRIORITY={debug:0,info:1,warn:2,error:3,fatal:4},LOG_LEVEL_COLORS={debug:"\x1B[36m",info:"\x1B[32m",warn:"\x1B[33m",error:"\x1B[31m",fatal:"\x1B[35m"}});function fold(value){return value.toLocaleLowerCase("tr")}function stripAnsi(value){return value.replace(ANSI_PATTERN,"")}function redactLogLine(line){let out=line;for(let{pattern,replace}of RAW_REDACTIONS)out=out.replace(pattern,replace);return out}function beginLoggerEmit(){loggerEmitDepth+=1}function endLoggerEmit(){loggerEmitDepth=Math.max(0,loggerEmitDepth-1)}function isLoggerEmitting(){return loggerEmitDepth>0}class ServerLogBuffer{records=[];capacity;maxLineLength;seq=0;evicted=0;subscribers=new Set;constructor(options={}){this.capacity=Math.max(1,options.capacity??DEFAULT_CAPACITY),this.maxLineLength=Math.max(80,options.maxLineLength??DEFAULT_MAX_LINE)}getCapacity(){return this.capacity}setCapacity(capacity){this.capacity=Math.max(1,capacity),this.trim()}trim(){if(this.records.length<=this.capacity)return;let overflow=this.records.length-this.capacity;this.records.splice(0,overflow),this.evicted+=overflow}truncate(message){if(message.length<=this.maxLineLength)return{message,truncated:!1};return{message:`${message.slice(0,this.maxLineLength)}\u2026`,truncated:!0}}push(record){this.seq+=1;let stored={...record,seq:this.seq};this.records.push(stored),this.trim();for(let subscriber of this.subscribers)try{subscriber(stored)}catch{}return stored}add(entry){let{message,truncated}=this.truncate(entry.message);return this.push({timestamp:entry.timestamp,level:entry.level,message,source:"logger",scope:entry.scope,service:entry.service,correlationId:entry.correlationId,context:entry.context,error:entry.error?{name:entry.error.name,message:entry.error.message,stack:entry.error.stack,code:entry.error.code}:void 0,caller:entry.caller?`${entry.caller.function} (${entry.caller.file}:${entry.caller.line})`:void 0,...truncated?{truncated:!0}:{}})}addRaw(text,source,timestamp){let cleaned=redactLogLine(stripAnsi(text)).replace(/\s+$/,"");if(cleaned.trim().length===0)return null;let{message,truncated}=this.truncate(cleaned);return this.push({timestamp:timestamp??new Date().toISOString(),level:source==="stderr"?"error":"info",message,source,...truncated?{truncated:!0}:{}})}matches(record,query,needle){if(query.levels&&query.levels.length>0&&!query.levels.includes(record.level))return!1;if(query.minLevel&&LOG_LEVEL_PRIORITY[record.level]<LOG_LEVEL_PRIORITY[query.minLevel])return!1;if(query.source&&record.source!==query.source)return!1;if(query.scope){let scope=record.scope??"";if(scope!==query.scope&&!scope.startsWith(`${query.scope}.`))return!1}if(needle){if(!fold([record.message,record.scope??"",record.service??"",record.error?.name??"",record.error?.message??"",record.correlationId??""].join(" ")).includes(needle))return!1}return!0}query(query={}){let limit=Math.min(Math.max(1,query.limit??200),1000),needle=query.search?.trim()?fold(query.search.trim()):null,filtered=this.records.filter((record)=>this.matches(record,query,needle)),window2,hasMore;if(query.after!==void 0){let fresh=filtered.filter((record)=>record.seq>query.after);hasMore=fresh.length>limit,window2=fresh.slice(0,limit)}else{let older=query.before!==void 0?filtered.filter((record)=>record.seq<query.before):filtered;hasMore=older.length>limit,window2=older.slice(Math.max(0,older.length-limit)).reverse()}return{records:window2,matched:filtered.length,buffered:this.records.length,capacity:this.capacity,evicted:this.evicted,latestSeq:this.seq,oldestSeq:this.records[0]?.seq??0,hasMore}}scopes(){let seen=new Set;for(let record of this.records)if(record.scope)seen.add(record.scope);return[...seen].sort()}levelCounts(){let counts={debug:0,info:0,warn:0,error:0,fatal:0};for(let record of this.records)counts[record.level]+=1;return counts}clear(){this.records=[]}subscribe(subscriber){return this.subscribers.add(subscriber),()=>{this.subscribers.delete(subscriber)}}subscriberCount(){return this.subscribers.size}}function getServerLogBuffer(options){if(!sharedBuffer)sharedBuffer=new ServerLogBuffer(options);else if(options?.capacity)sharedBuffer.setCapacity(options.capacity);return sharedBuffer}function attachStreamCapture(buffer){if(detachCapture)return detachCapture;let wire=(stream,source)=>{let original=stream.write.bind(stream),patched=(chunk,encoding,callback)=>{if(!isLoggerEmitting())try{let text=typeof chunk==="string"?chunk:chunk instanceof Uint8Array?new TextDecoder().decode(chunk):"";for(let line of text.split(`
|
|
16
16
|
`))if(line.trim().length>0)buffer.addRaw(line,source)}catch{}return original(chunk,encoding,callback)};return stream.write=patched,()=>{stream.write=original}},restoreOut=wire(process.stdout,"stdout"),restoreErr=wire(process.stderr,"stderr");return detachCapture=()=>{restoreOut(),restoreErr(),detachCapture=null},detachCapture}var DEFAULT_CAPACITY=2000,DEFAULT_MAX_LINE=8000,ANSI_PATTERN,RAW_REDACTIONS,loggerEmitDepth=0,sharedBuffer=null,detachCapture=null;var init_ServerLogBuffer=__esm(()=>{init_types();ANSI_PATTERN=/\x1B\[[0-9;]*[A-Za-z]/g;RAW_REDACTIONS=[{pattern:/\b(bearer)\s+[A-Za-z0-9._\-+/=]{8,}/gi,replace:"$1 [REDACTED]"},{pattern:/\beyJ[A-Za-z0-9._-]{10,}/g,replace:"[REDACTED_JWT]"},{pattern:/\b(sk|pk|rk)-[A-Za-z0-9._-]{12,}/g,replace:"[REDACTED_KEY]"},{pattern:/\b(gh[pousr]|xox[baprs])[-_][A-Za-z0-9]{12,}/g,replace:"[REDACTED_KEY]"},{pattern:/\b(password|passwd|secret|token|api[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret)\b("?\s*[:=]\s*"?)([^\s",}]+)/gi,replace:"$1$2[REDACTED]"},{pattern:/\b([a-z][a-z0-9+.-]*:\/\/[^:/\s]+):([^@\s]+)@/gi,replace:"$1:[REDACTED]@"}]});function redactSensitiveData(obj,redactKeys=DEFAULT_REDACT_KEYS,seen=new WeakSet){if(obj===null||obj===void 0)return obj;if(obj instanceof Error){let code=obj.code;return redactSensitiveData({name:obj.name,message:obj.message,stack:obj.stack,...code!==void 0?{code}:{}},redactKeys,seen)}if(typeof obj==="bigint")return obj.toString();if(typeof obj!=="object")return obj;if(seen.has(obj))return"[Circular]";if(seen.add(obj),Array.isArray(obj))return obj.map((item)=>redactSensitiveData(item,redactKeys,seen));let proto=Object.getPrototypeOf(obj);if(proto!==Object.prototype&&proto!==null)return typeof obj.toISOString==="function"?obj.toISOString():obj;let result={};for(let[key,value]of Object.entries(obj))if(redactKeys.some((redactKey)=>key.toLowerCase().includes(redactKey.toLowerCase())))result[key]="[REDACTED]";else if(value instanceof Error||typeof value==="object"&&value!==null)result[key]=redactSensitiveData(value,redactKeys,seen);else result[key]=value;return result}function getCallerInfo(){let stack=Error().stack;if(!stack)return{file:"unknown",line:0,function:"unknown"};let lines=stack.split(`
|
|
17
17
|
`).slice(1);for(let line of lines){let match=line.match(/at\s+(?:(.+?)\s+)?\(?(.+?):(\d+):(\d+)\)?/);if(!match)continue;let[,fnName,filePath,lineNum]=match,fileName=filePath?filePath.split("/").pop()||filePath:"unknown";if(LOGGER_INTERNAL_FILES.includes(fileName))continue;return{file:fileName,line:parseInt(lineNum||"0",10),function:fnName?.replace(/^Object\./,"")||"anonymous"}}return{file:"unknown",line:0,function:"unknown"}}function formatCause(cause,depth,seen){if(cause===void 0||cause===null)return;if(depth>4||seen.has(cause))return;if(seen.add(cause),cause instanceof Error)return{name:cause.name,message:cause.message,code:cause.code,cause:formatCause(cause.cause,depth+1,seen)};return{name:"Error",message:typeof cause==="string"?cause:String(cause)}}function formatError(error){if(error instanceof Error)return{name:error.name,message:error.message,stack:error.stack,code:error.code,cause:formatCause(error.cause,1,new Set([error]))};if(typeof error==="string")return{name:"Error",message:error};return{name:"UnknownError",message:String(error)}}function mergeContext(base,additional){if(!base&&!additional)return;if(!base)return additional;if(!additional)return base;return{...base,...additional}}function formatDuration(ms){if(ms<1)return`${(ms*1000).toFixed(2)}\xB5s`;if(ms<1000)return`${ms.toFixed(2)}ms`;return`${(ms/1000).toFixed(2)}s`}function safeStringify(obj,indent){let seen=new WeakSet;return JSON.stringify(obj,(_,value)=>{if(typeof value==="object"&&value!==null){if(seen.has(value))return"[Circular]";seen.add(value)}if(typeof value==="bigint")return value.toString();if(value instanceof Error)return{name:value.name,message:value.message,stack:value.stack};return value},indent)}var DEFAULT_REDACT_KEYS,LOGGER_INTERNAL_FILES;var init_utils=__esm(()=>{DEFAULT_REDACT_KEYS=["password","secret","token","apiKey","api_key","authorization","cookie","credit_card","creditCard","ssn","privateKey","private_key"];LOGGER_INTERNAL_FILES=["Logger.ts","transports.ts","utils.ts"]});class ConsoleTransport{name="console";colorize;prettyPrint;constructor(options={}){this.colorize=options.colorize??!0,this.prettyPrint=options.prettyPrint??!0}log(entry){beginLoggerEmit();try{if(this.prettyPrint)this.logPretty(entry);else this.logJson(entry)}finally{endLoggerEmit()}}logJson(entry){let output=safeStringify(entry);this.getConsoleMethod(entry.level)(output)}logPretty(entry){let method=this.getConsoleMethod(entry.level),color=this.colorize?LOG_LEVEL_COLORS[entry.level]:"",reset=this.colorize?RESET_COLOR:"",dim=this.colorize?DIM_COLOR:"",bold=this.colorize?BOLD_COLOR:"",time=new Date(entry.timestamp).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"}),levelStr=entry.level.toUpperCase().padEnd(5),serviceStr=entry.service?`[${entry.service}]`:"",correlationStr=entry.correlationId?`${dim}(${entry.correlationId.slice(0,8)})${reset}`:"",durationStr=entry.duration!==void 0?`${dim}${formatDuration(entry.duration)}${reset}`:"",line=`${dim}${time}${reset} ${color}${bold}${levelStr}${reset} ${serviceStr}${correlationStr} ${entry.message} ${durationStr}`;if(method(line.trim()),entry.caller)method(` ${dim}at ${entry.caller.function} (${entry.caller.file}:${entry.caller.line})${reset}`);if(entry.context&&Object.keys(entry.context).length>0)method(` ${dim}context:${reset}`,entry.context);if(entry.error){if(method(` ${color}${entry.error.name}: ${entry.error.message}${reset}`),entry.error.stack){let stackLines=entry.error.stack.split(`
|
|
18
|
-
`).slice(1,4);for(let stackLine of stackLines)method(` ${dim}${stackLine.trim()}${reset}`)}let cause=entry.error.cause,indent=" ";while(cause){indent+=" ";let code=cause.code!==void 0?` [${cause.code}]`:"";method(`${indent}${color}caused by: ${cause.name}${code}: ${cause.message}${reset}`),cause=cause.cause}}}getConsoleMethod(level){switch(level){case"debug":return console.debug.bind(console);case"info":return console.info.bind(console);case"warn":return console.warn.bind(console);case"error":case"fatal":return console.error.bind(console);default:return console.log.bind(console)}}}class ServerLogTransport{name="server-log-buffer";buffer;constructor(buffer){this.buffer=buffer}log(entry){this.buffer.add(entry)}}class DatabaseAuditTransport{name="database";db;table;enabled;dedupEnabled;dedupWindowMs;dedupSlots=new Map;lastSweep=0;constructor(options){this.db=options.db,this.table=options.table,this.enabled=options.enabled??!0,this.dedupEnabled=options.dedup?.enabled??!1,this.dedupWindowMs=Math.max(1,options.dedup?.windowSeconds??60)*1000}setDb(db){this.db=db}setTable(table){this.table=table}setEnabled(enabled){this.enabled=enabled}setDedup(dedup){if(this.dedupEnabled=dedup.enabled??this.dedupEnabled,dedup.windowSeconds!=null)this.dedupWindowMs=Math.max(1,dedup.windowSeconds)*1000}isDedupable(entry){return this.dedupEnabled&&(entry.category==="auth"||entry.category==="authz"||entry.category==="security_anomaly")}sweep(now){if(now-this.lastSweep<this.dedupWindowMs)return;this.lastSweep=now;for(let[key,slot]of this.dedupSlots)if(slot.expiresAt<=now)this.dedupSlots.delete(key)}async write(entry){if(!this.enabled||!this.db||!this.table)return;try{let now=Date.now();if(this.isDedupable(entry)){this.sweep(now);let key=`${entry.ipAddress}|${entry.operation}|${entry.summary}|${entry.userId??""}`,slot=this.dedupSlots.get(key);if(slot&&slot.expiresAt>now){slot.count+=1,await this.bumpOccurrence(slot.rowId,slot.count,now);return}this.dedupSlots.set(key,{rowId:entry.id,count:1,expiresAt:now+this.dedupWindowMs})}await this.db.insert(this.table).values({id:entry.id,entityId:entry.entityId,entityName:entry.entityName,operationType:entry.operation,userId:entry.userId,ipAddress:entry.ipAddress,userAgent:entry.userAgent,summary:entry.summary,severity:entry.severity,category:entry.category,occurrenceCount:1,oldValues:entry.oldValues,newValues:entry.newValues,path:entry.path,query:entry.query})}catch(error){console.error("Audit log write failed:",error)}}async bumpOccurrence(rowId,count,nowMs){try{let{eq}=await import("drizzle-orm"),idCol=this.table.id;await this.db.update(this.table).set({occurrenceCount:count,lastOccurrenceAt:new Date(nowMs)}).where(eq(idCol,rowId))}catch(error){console.error("Audit dedup update failed:",error)}}}class ConsoleAuditTransport{name="console-audit";enabled;constructor(options={}){this.enabled=options.enabled??!0}write(entry){if(!this.enabled)return;let reset=RESET_COLOR,dim=DIM_COLOR,color={info:"\x1B[35m",low:"\x1B[90m",medium:"\x1B[33m",high:"\x1B[31m",critical:"\x1B[1m\x1B[31m"}[entry.severity]??"\x1B[35m",sev=entry.severity.toUpperCase(),actor=entry.userId||"anonymous",cat=entry.category;console.log(`${dim}${entry.timestamp}${reset} ${color}AUDIT\xB7${sev}${reset} ${dim}(${cat})${reset} [${entry.operation}] ${entry.entityName}${entry.entityId?`:${entry.entityId}`:""} ${dim}by ${actor}${reset}${entry.summary?` ${dim}\u2014${reset} ${entry.summary}`:""}`)}}var init_transports=__esm(()=>{init_ServerLogBuffer();init_types();init_utils()});class Logger{config;transports;auditTransports;context;correlationId;static instance=null;constructor(config={},context={},correlationId){this.config={...DEFAULT_CONFIG,...config},this.config.redactKeys=[...new Set([...DEFAULT_REDACT_KEYS,...config.redactKeys||[]])],this.context=context,this.correlationId=correlationId,this.transports=[new ConsoleTransport({colorize:this.config.colorize,prettyPrint:this.config.prettyPrint})],this.auditTransports=[new ConsoleAuditTransport({enabled:this.config.prettyPrint})]}static getInstance(config){if(!Logger.instance)Logger.instance=new Logger(config);return Logger.instance}static resetInstance(){Logger.instance=null}configure(config){return this.config={...this.config,...config},this.config.redactKeys=[...new Set([...DEFAULT_REDACT_KEYS,...config.redactKeys||this.config.redactKeys||[]])],this.transports=[new ConsoleTransport({colorize:this.config.colorize,prettyPrint:this.config.prettyPrint}),...this.transports.filter((t)=>t.name!=="console")],this}child(context,correlationId){let childLogger=new Logger(this.config,mergeContext(this.context,context)||{},correlationId||this.correlationId);return childLogger.transports=this.transports,childLogger.auditTransports=this.auditTransports,childLogger}withCorrelationId(correlationId){return this.child({},correlationId)}addTransport(transport){this.transports.push(transport)}addAuditTransport(transport){this.auditTransports.push(transport)}setLevel(level){this.config.level=level}setAuditEnabled(enabled){this.config.auditEnabled=enabled}isAuditEnabled(){return this.config.auditEnabled}setAuditSuppressReasons(reasons){this.config.auditSuppressReasons=reasons}setAuditMinSeverity(severity){this.config.auditMinSeverity=severity}shouldLog(level){return LOG_LEVEL_PRIORITY[level]>=LOG_LEVEL_PRIORITY[this.config.level]}shouldLogScope(scope){if(!scope)return!0;return matchesScope(scope,this.config.enabledScopes)}setEnabledScopes(scopes){this.config.enabledScopes=scopes}getEnabledScopes(){return this.config.enabledScopes}scoped(scope){return new ScopedLogger(this,scope)}createEntry(level,message,context,error,startTime,scope){let entry={timestamp:new Date().toISOString(),level,message,scope,service:this.config.service,correlationId:this.correlationId},mergedContext=mergeContext(this.context,context);if(mergedContext&&Object.keys(mergedContext).length>0)entry.context=redactSensitiveData(mergedContext,this.config.redactKeys);if(this.config.includeCallerInfo)entry.caller=getCallerInfo();if(error)entry.error=formatError(error);if(startTime!==void 0)entry.duration=performance.now()-startTime;return entry}log(level,message,context,error,startTime,scope){if(!this.shouldLog(level))return;if(!this.shouldLogScope(scope))return;let entry=this.createEntry(level,message,context,error,startTime,scope);for(let transport of this.transports)try{transport.log(entry)}catch(err){console.error(`Logger transport "${transport.name}" failed:`,err)}}debug(message,context){this.log("debug",message,context)}info(message,context){this.log("info",message,context)}warn(message,context){this.log("warn",message,context)}error(message,error,context){this.log("error",message,context,error)}fatal(message,error,context){this.log("fatal",message,context,error)}time(label){let start=performance.now();return()=>{this.log("debug",`${label} completed`,void 0,void 0,start)}}async timeAsync(label,fn,context){let start=performance.now();try{let result=await fn();return this.log("debug",`${label} completed`,context,void 0,start),result}catch(error){throw this.log("error",`${label} failed`,context,error,start),error}}request(options){let level=options.statusCode>=500?"error":options.statusCode>=400?"warn":"info";this.log(level,`${options.method} ${options.path} ${options.statusCode}`,{method:options.method,path:options.path,statusCode:options.statusCode,durationMs:options.duration,correlationId:options.correlationId,userId:options.userId,ip:options.ip,userAgent:options.userAgent})}db(options){let level=options.error?"error":"debug";this.log(level,`DB ${options.operation} on ${options.table}`,{operation:options.operation,table:options.table,durationMs:options.duration,rowCount:options.rowCount},options.error)}async flush(){for(let transport of this.transports)if(transport.flush)await transport.flush()}async audit(options){let summary=options.summary||`${options.operation} on ${options.entityName}`;if(this.config.auditSuppressReasons?.includes(summary))return;let derived=classifyAudit(options.operation,summary),severity=options.severity??derived.severity,category=options.category??derived.category;if(severityRank(severity)<severityRank(this.config.auditMinSeverity))return;let entry={id:randomId(),timestamp:new Date().toISOString(),entityName:options.entityName,entityId:options.entityId??null,operation:options.operation,userId:options.userId??null,summary,severity,category,oldValues:redactSensitiveData(options.oldValues||{},this.config.redactKeys),newValues:redactSensitiveData(options.newValues||{},this.config.redactKeys),ipAddress:options.ipAddress||"unknown",userAgent:options.userAgent||"unknown",path:options.path||"",query:options.query||"",correlationId:this.correlationId};for(let transport of this.auditTransports)try{await transport.write(entry)}catch(err){console.error(`Audit transport "${transport.name}" failed:`,err)}}auditOnly(options){this.audit(options)}async trace(options){let shouldLog=options.log!==!1,shouldAudit=options.writeAudit===!0||options.writeAudit!==!1&&this.config.auditEnabled&&options.audit;if(shouldLog)this.log(options.level||"info",options.message,options.context,options.error);if(shouldAudit&&options.audit)await this.audit(options.audit)}traceSync(options){let shouldLog=options.log!==!1,shouldAudit=options.writeAudit===!0||options.writeAudit!==!1&&this.config.auditEnabled&&options.audit;if(shouldLog)this.log(options.level||"info",options.message,options.context,options.error);if(shouldAudit&&options.audit)this.audit(options.audit)}}class ScopedLogger{parent;scope;constructor(parent,scope){this.parent=parent,this.scope=scope}debug(message,context){this.parent.log("debug",message,context,void 0,void 0,this.scope)}info(message,context){this.parent.log("info",message,context,void 0,void 0,this.scope)}warn(message,context){this.parent.log("warn",message,context,void 0,void 0,this.scope)}error(message,error,context){this.parent.log("error",message,context,error,void 0,this.scope)}}var DEFAULT_CONFIG,logger;var init_Logger=__esm(()=>{init_auditTaxonomy();init_scopes();init_transports();init_types();init_utils();DEFAULT_CONFIG={level:"info",service:"nucleus",environment:"development",redactKeys:[],colorize:!0,prettyPrint:!0,includeCallerInfo:!0,asyncBufferSize:100,flushIntervalMs:1000,auditEnabled:!1,auditSuppressReasons:DEFAULT_AUDIT_SUPPRESS_REASONS,auditMinSeverity:"info",enabledScopes:["*"]};logger=Logger.getInstance()});var require_auto_promise=__commonJS((exports,module)=>{var slice=Array.prototype.slice;module.exports=function(fn,makeResult){return function(){var promise,args=arguments,n=args.length;if(n!==0&&typeof args[n-1]!=="function")args=slice.call(arguments),promise=new Promise(function(resolve,reject){args.push(function(err,result){if(err!=null)reject(err);else resolve(makeResult!==void 0?makeResult.apply(this,slice.call(arguments,1)):result)})});return fn.apply(this,args),promise}}});var require_smb2_message=__commonJS((exports,module)=>{var protocolId=Buffer.from([254,83,77,66]),headerTranslates={Command:{NEGOTIATE:0,SESSION_SETUP:1,LOGOFF:2,TREE_CONNECT:3,TREE_DISCONNECT:4,CREATE:5,CLOSE:6,FLUSH:7,READ:8,WRITE:9,LOCK:10,IOCTL:11,CANCEL:12,ECHO:13,QUERY_DIRECTORY:14,CHANGE_NOTIFY:15,QUERY_INFO:16,SET_INFO:17,OPLOCK_BREAK:18}},headerLength=64,headerSync=function(processId,sessionId){return[["ProtocolId",4,protocolId],["StructureSize",2,headerLength],["CreditCharge",2,0],["Status",4,0],["Command",2],["Credit",2,126],["Flags",4,0],["NextCommand",4,0],["MessageId",4],["MessageIdHigh",4,0],["ProcessId",4,processId],["TreeId",4,0],["SessionId",8,sessionId],["Signature",16,0]]},headerASync=function(processId,sessionId){return[["ProtocolId",4,protocolId],["StructureSize",2,headerLength],["CreditCharge",2,0],["Status",4,0],["Command",2],["Credit",2,126],["Flags",4,0],["NextCommand",4,0],["MessageId",4],["MessageIdHigh",4,0],["AsyncId",8],["SessionId",8,sessionId],["Signature",16,0]]},SMB2Message=module.exports=function(options){if(this.headers={},options&&options.headers)this.setHeaders(options.headers);if(this.request={},options&&options.request)this.setRequest(options.request);this.response={}},proto=SMB2Message.prototype={};proto.setHeaders=function(obj){for(var key in obj)this.headers[key]=obj[key];this.structure=__require("../structures/"+this.headers.Command.toLowerCase())};proto.getHeaders=function(){return this.headers};proto.setRequest=function(request){this.request=request};proto.getResponse=function(){return this.response};proto.getBuffer=function(connection){var buffer=Buffer.allocUnsafe(65535),length=0;if(!this.isMessageIdSetted)this.isMessageIdSetted=!0,this.headers.MessageId=connection.messageId++;length+=writeHeaders(this,buffer),length+=writeRequest(this,buffer,headerLength);var output=Buffer.allocUnsafe(length);return buffer.copy(output,0,0,length),output};proto.parseBuffer=function(buffer){readHeaders(this,buffer),readResponse(this,buffer,headerLength)};function dataToBuffer(data,length){if(Buffer.isBuffer(data))return data;if(typeof data==="string")return Buffer.from(data);var result=Buffer.allocUnsafe(length);for(var i=0;i<length;i++)result.writeUInt8(255&data>>i*8,i);return result}function bufferToData(buffer){if(!Buffer.isBuffer(buffer))return buffer;var result=0;for(var i=0;i<buffer.length;i++)result+=buffer.readUInt8(i)<<i*8;return result}function writeData(buffer,data,offset,length){dataToBuffer(data,length).copy(buffer,offset,0)}function readData(buffer,offset,length){return buffer.slice(offset,offset+length)}function translate(key,value){if(headerTranslates[key]&&typeof headerTranslates[key][value]<"u")return headerTranslates[key][value];return value}function unTranslate(key,value){if(headerTranslates[key]){for(var t in headerTranslates[key])if(headerTranslates[key][t]===value)return t}return null}function readHeaders(message,buffer){var header=(message.isAsync?headerASync:headerSync)(message.ProcessId,message.SessionId),offset=0;for(var i in header){var key=header[i][0],length=header[i][1];if(message.headers[key]=readData(buffer,offset,length),length<=8)message.headers[key]=unTranslate(key,bufferToData(message.headers[key]))||message.headers[key];offset+=length}message.structure=__require("../structures/"+message.headers.Command.toLowerCase())}function writeHeaders(message,buffer){var header=(message.isAsync?headerASync:headerSync)(message.ProcessId,message.SessionId),offset=0;for(var i in header){var key=header[i][0],length=header[i][1],defaultValue=header[i][2]||0;writeData(buffer,translate(key,message.headers[key]||defaultValue),offset,length),offset+=length}return offset}function readResponse(message,buffer,offset){for(var i in message.structure.response){var key=message.structure.response[i][0],length=message.structure.response[i][1]||1;if(typeof length==="string")length=bufferToData(message.response[length]);message.response[key]=readData(buffer,offset,length),offset+=length}}function writeRequest(message,buffer,offset){var initOffset=offset,needsRewrite=!1,tmpBuffer=Buffer.allocUnsafe(buffer.length);offset=0;for(var i in message.structure.request){var key=message.structure.request[i][0],length=message.structure.request[i][1]||1,defaultValue=message.structure.request[i][2]||0;if(typeof length==="string"){if(message.request[key]=message.request[key]||"",message.request[length]!==message.request[key].length)message.request[length]=message.request[key].length,needsRewrite=!0;length=message.request[key].length}else message.request[key]=message.request[key]||defaultValue;writeData(tmpBuffer,message.request[key],offset,length),offset+=length}if(needsRewrite)writeRequest(message,tmpBuffer,0);return tmpBuffer.copy(buffer,initOffset,0,offset),offset}});var require_smb2_forge=__commonJS((exports,module)=>{var SMB2Message=require_smb2_message(),SMB2Forge=module.exports={};SMB2Forge.request=function(messageName,params,connection,cb){var msg=__require("../messages/"+messageName),smbMessage=msg.generate(connection,params);sendNetBiosMessage(connection,smbMessage);var error=Error();error.messageName=messageName,error.params=params,getResponse(connection,smbMessage.getHeaders().MessageId,msg.parse(connection,cb,error))};SMB2Forge.response=function(c){return c.responses={},c.responsesCB={},c.responseBuffer=Buffer.allocUnsafe(0),function(response){c.responseBuffer=Buffer.concat([c.responseBuffer,response]);var extract=!0;while(extract)if(extract=!1,c.responseBuffer.length>=4){var msgLength=(c.responseBuffer.readUInt8(1)<<16)+c.responseBuffer.readUInt16BE(2);if(c.responseBuffer.length>=msgLength+4){extract=!0;var r=c.responseBuffer.slice(4,msgLength+4),message=new SMB2Message;if(message.parseBuffer(r),c.debug)console.log("--response"),console.log(r.toString("hex"));var mId=message.getHeaders().MessageId.toString("hex");if(c.responsesCB[mId])c.responsesCB[mId](message),delete c.responsesCB[mId];else c.responses[mId]=message;c.responseBuffer=c.responseBuffer.slice(msgLength+4)}}}};function sendNetBiosMessage(connection,message){var smbRequest=message.getBuffer(connection);if(connection.debug)console.log("--request"),console.log(smbRequest.toString("hex"));var buffer=Buffer.allocUnsafe(smbRequest.length+4);return buffer.writeUInt8(0,0),buffer.writeUInt8((16711680&smbRequest.length)>>16,1),buffer.writeUInt16BE(65535&smbRequest.length,2),smbRequest.copy(buffer,4,0,smbRequest.length),connection.newResponse=!1,connection.socket.write(buffer),!0}function getResponse(c,mId,cb){var messageId=Buffer.allocUnsafe(4);if(messageId.writeUInt32LE(mId,0),messageId=messageId.toString("hex"),c.responses[messageId])cb(c.responses[messageId]),delete c.responses[messageId];else c.responsesCB[messageId]=cb}});var require_smb2_connection=__commonJS((exports,module)=>{var net=__require("net"),SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,SMB2Connection=module.exports={};SMB2Connection.close=function(connection){if(clearAutoCloseTimeout(connection),connection.connected)connection.connected=!1,connection.socket.end()};SMB2Connection.requireConnect=function(method){return function(){var connection=this,args=Array.prototype.slice.call(arguments);connect(connection,function(err){var cb=args.pop();if(typeof cb!=="function")args.push(cb),cb=function(err2){if(err2){if(!(err2 instanceof Error))err2=Error(String(err2));throw err2}};if(cb=scheduleAutoClose(connection,cb),args.push(cb),err)cb(err);else method.apply(connection,args)})}};SMB2Connection.init=function(connection){connection.connected=!1,connection.socket=new net.Socket({allowHalfOpen:!0}),connection.socket.on("data",SMB2Forge.response(connection)),connection.errorHandler=[],connection.socket.on("error",function(err){if(connection.errorHandler.length>0)connection.errorHandler[0].call(null,err);if(connection.debug)console.log("-- error"),console.log(arguments)})};function connect(connection,cb){if(connection.connected){cb&&cb(null);return}cb=scheduleAutoClose(connection,cb),connection.messageId=0,connection.SessionId=Math.floor(Math.random()*256)&255,connection.socket.connect(connection.port,connection.ip),SMB2Request("negotiate",{},connection,function(err){if(err)cb&&cb(err);else SMB2Request("session_setup_step1",{},connection,function(err2){if(err2)cb&&cb(err2);else SMB2Request("session_setup_step2",{},connection,function(err3){if(err3)cb&&cb(err3);else SMB2Request("tree_connect",{},connection,function(err4){if(err4)cb&&cb(err4);else connection.connected=!0,cb&&cb(null)})})})})}function clearAutoCloseTimeout(connection){if(connection.scheduledAutoClose)clearTimeout(connection.scheduledAutoClose),connection.scheduledAutoClose=null}function setAutoCloseTimeout(connection){if(clearAutoCloseTimeout(connection),connection.autoCloseTimeout!==0)connection.scheduledAutoClose=setTimeout(function(){SMB2Connection.close(connection)},connection.autoCloseTimeout)}function scheduleAutoClose(connection,cb){return addErrorListener(connection,cb),clearAutoCloseTimeout(connection),function(){removeErrorListener(connection),setAutoCloseTimeout(connection),cb.apply(null,arguments)}}function addErrorListener(connection,callback){connection.errorHandler.unshift(callback)}function removeErrorListener(connection){connection.errorHandler.shift()}});var require_disconnect=__commonJS((exports,module)=>{var SMB2Connection=require_smb2_connection();module.exports=function(){SMB2Connection.close(this)}});var require_exists=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request;module.exports=function(path,cb){var connection=this;SMB2Request("open",{path},connection,function(err,file){if(err!=null){if(err.code==="STATUS_OBJECT_NAME_NOT_FOUND"||err.code==="STATUS_OBJECT_PATH_NOT_FOUND")return cb&&cb(null,!1);return cb&&cb(err)}SMB2Request("close",file,connection,function(){cb&&cb(null,!0)})})}});var require_bigint=__commonJS((exports,module)=>{var BigInt2=module.exports=function(n,v){if(BigInt2.isBigInt(n))this.buffer=Buffer.allocUnsafe(n.buffer.length),n.buffer.copy(this.buffer,0),this.sign=n.sign;else if(this.buffer=Buffer.alloc(n),this.sign=1,v=v||0,v!==0){if(v<0)this.sign=-1,v=-v;v=v.toString(16);var size=Math.ceil(v.length/2),carry=size*2-v.length;for(var i=0;i<size;i++){var start=(size-i-1)*2-carry;this.buffer.writeUInt8(parseInt(start===-1?v.substr(0,1):v.substr(start,2),16),i)}}};BigInt2.isBigInt=function(v){return v&&v.buffer&&Buffer.isBuffer(v.buffer)};BigInt2.toBigInt=function(n,v){return new BigInt2(n,v)};BigInt2.fromBuffer=function(b,sign){sign=typeof sign>"u"?1:sign;var bi=new BigInt2(0);return bi.sign=sign,bi.buffer=b,bi};BigInt2.prototype.add=function(v){if(!BigInt2.isBigInt(v))v=BigInt2.toBigInt(this.buffer.length,v);if(this.sign!==v.sign)return this.neg().sub(v);var carry=0,n=Math.max(v.buffer.length,this.buffer.length),result=new BigInt2(n);for(var i=0;i<n;i++){var r=(i<this.buffer.length?this.buffer.readUInt8(i):0)+(i<v.buffer.length?v.buffer.readUInt8(i):0)+carry;result.buffer.writeUInt8(r&255,i),carry=r>>8}return result.sign=this.sign,result};BigInt2.prototype.neg=function(){var result=new BigInt2(this);return result.sign*=-1,result};BigInt2.prototype.abs=function(){var result=new BigInt2(this);return result.sign=1,result};BigInt2.prototype.sub=function(v){if(!BigInt2.isBigInt(v))v=BigInt2.toBigInt(this.buffer.length,v);if(this.sign!==v.sign)return this.add(v.neg());var carry=0,a=new BigInt2(this),b=new BigInt2(v),n=Math.max(a.buffer.length,b.buffer.length),result=new BigInt2(n),sign=this.sign;if(a.abs().lt(b.abs())){var t=a;a=b,b=t,sign*=-1}for(var i=0;i<n;i++){var va=i<a.buffer.length?a.buffer.readUInt8(i):0,vb=i<b.buffer.length?b.buffer.readUInt8(i):0,c=0,r=va-vb-carry;while(r<0)r+=255,c--;result.buffer.writeUInt8(r&255,i),carry=(r>>8)+c}return result.sign=sign,result};BigInt2.prototype.toBuffer=function(){return this.buffer};BigInt2.prototype.toNumber=function(){var b=Buffer.allocUnsafe(this.buffer.length);for(var i=0;i<this.buffer.length;i++)b.writeUInt8(this.buffer.readUInt8(this.buffer.length-i-1),i);return parseInt(b.toString("hex"),16)};BigInt2.prototype.compare=function(v){if(!BigInt2.isBigInt(v))v=BigInt2.toBigInt(this.buffer.length,v);var n=Math.max(v.buffer.length,this.buffer.length);if(this.sign>v.sign)return 1;if(this.sign<v.sign)return-1;for(var i=n-1;i>=0;i--){var a=i<this.buffer.length?this.buffer.readUInt8(i):0,b=i<v.buffer.length?v.buffer.readUInt8(i):0;if(a!==b)return a>b?this.sign:-this.sign}return 0};BigInt2.prototype.lt=function(v){return this.compare(v)<0};BigInt2.prototype.le=function(v){return this.compare(v)<=0};BigInt2.prototype.gt=function(v){return this.compare(v)>0};BigInt2.prototype.ge=function(v){return this.compare(v)>=0}});var require_constants=__commonJS((exports,module)=>{module.exports={FILE_SUPERSEDE:0,FILE_OPEN:1,FILE_CREATE:2,FILE_OPEN_IF:3,FILE_OVERWRITE:4,FILE_OVERWRITE_IF:5,MAX_READ_LENGTH:65536,MAX_WRITE_LENGTH:65423,FILE_SHARE_NONE:0,FILE_SHARE_READ:1,FILE_SHARE_WRITE:2,FILE_SHARE_DELETE:4,DELETE:65536,FILE_APPEND_DATA:4,FILE_DELETE_CHILD:64,FILE_READ_ATTRIBUTES:128,FILE_READ_DATA:1,FILE_READ_EA:8,FILE_WRITE_ATTRIBUTES:256,FILE_WRITE_DATA:2,FILE_WRITE_EA:16,READ_CONTROL:131072,SYNCHRONIZE:1048576,WRITE_DAC:262144,DIRECTORY:16}});var require_rename=__commonJS((exports,module)=>{var BigInt2=require_bigint(),SMB2Request=require_smb2_forge().request,constants=require_constants();module.exports=function(oldPath,newPath,options,cb){if(typeof options==="function")cb=options,options={};var connection=this;SMB2Request("open_folder",{path:oldPath},connection,function(err,file){if(err)SMB2Request("create",{path:oldPath,createDisposition:constants.FILE_OPEN,shareAccess:constants.FILE_SHARE_DELETE},connection,function(err2,file2){if(err2)cb&&cb(err2);else rename_(connection,file2,newPath,options,cb)});else rename_(connection,file,newPath,options,cb)})};function rename_(connection,file,newPath,options,cb){SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileRenameInformation",Buffer:renameBuffer(newPath,options)},connection,function(err){SMB2Request("close",file,connection,function(){if(err)cb&&cb(err);else cb&&cb(null)})})}function renameBuffer(newPath,options){var filename=Buffer.from(newPath,"ucs2");return Buffer.concat([new BigInt2(1,options.replace?1:0).toBuffer(),new BigInt2(7,0).toBuffer(),new BigInt2(8,0).toBuffer(),new BigInt2(4,filename.length).toBuffer(),filename])}});var require_readFile=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint(),MAX_READ_LENGTH=require_constants().MAX_READ_LENGTH;module.exports=function(filename,options,cb){var connection=this;if(typeof options==="function")cb=options,options={};SMB2Request("open",{path:filename},connection,function(err,file){if(err)cb&&cb(err);else{var fileLength=0,offset=new BigInt2(8),stop=!1,nbRemainingPackets=0;for(var i=0;i<file.EndofFile.length;i++)fileLength+=file.EndofFile[i]*Math.pow(2,i*8);var result=Buffer.allocUnsafe(fileLength),callback=function(offset2){return function(err2,content){if(stop)return;if(err2)cb&&cb(err2),stop=!0;else content.copy(result,offset2.toNumber()),nbRemainingPackets--,checkDone()}},checkDone=function(){if(stop)return;if(createPackets(),nbRemainingPackets===0&&offset.ge(fileLength))SMB2Request("close",file,connection,function(){if(options.encoding)result=result.toString(options.encoding);cb&&cb(null,result)})},createPackets=function(){while(nbRemainingPackets<connection.packetConcurrency&&offset.lt(fileLength)){var rest=offset.sub(fileLength).neg(),packetSize=rest.gt(MAX_READ_LENGTH)?MAX_READ_LENGTH:rest.toNumber();SMB2Request("read",{FileId:file.FileId,Length:packetSize,Offset:offset.toBuffer()},connection,callback(offset)),offset=offset.add(packetSize),nbRemainingPackets++}};checkDone()}})}});var require_createReadStream=__commonJS((exports,module)=>{var Readable=__require("stream").Readable,BigInt2=require_bigint(),request=require_smb2_forge().request,MAX_READ_LENGTH=require_constants().MAX_READ_LENGTH;module.exports=function(path,options,cb){if(typeof options==="function")cb=options,options={};else if(options==null)options={};var connection=this,fd=options.fd,isFd=fd!=null,shouldClose=!isFd||options.autoClose==null||options.autoClose;function onOpen(err,file){if(err!=null)return cb(err);var offset=options.start||0,fileSize=BigInt2.fromBuffer(file.EndofFile).toNumber(),end=fileSize;if(options.end<end)end=options.end+1;var close=request.bind(void 0,"close",file,connection),stream=new Readable;if(stream.fileSize=fileSize,shouldClose)stream._destroy=function(err2,cb2){close(function(err22){if(err22!=null)return cb2(err22);cb2(err2)})};var running=!1;stream._read=function(size){if(running)return;if(offset>=end)return shouldClose?close(function(){stream.push(null)}):stream.push(null);running=!0,request("read",{FileId:file.FileId,Length:Math.min(MAX_READ_LENGTH,size,end-offset),Offset:new BigInt2(8,offset).toBuffer()},connection,function(err2,content){if(running=!1,err2!=null)return process.nextTick(stream.emit.bind(stream,"error",err2));offset+=content.length,stream.push(content)})},cb(null,stream)}if(isFd)onOpen(null,fd);else request("open",{path},connection,onOpen)}});var require_parse_flags=__commonJS((exports,module)=>{var c=require_constants();module.exports=function(flags){var chars={__proto__:null};for(var i=0,n=flags.length;i<n;++i)chars[flags[i]]=!0;if("r"in chars)return c.FILE_OPEN;if("x"in chars)return c.FILE_CREATE;if("a"in chars)return c.FILE_OPEN_IF;if("w"in chars)return c.FILE_OVERWRITE_IF;throw Error("invalid flags")}});var require_createWriteStream=__commonJS((exports,module)=>{var Writable=__require("stream").Writable,BigInt2=require_bigint(),constants=require_constants(),parseFlags=require_parse_flags(),request=require_smb2_forge().request;module.exports=function(path,options,cb){if(typeof options==="function")cb=options,options={};var connection=this,fd=options.fd,isFd=fd!=null,shouldClose=!isFd||options.autoClose==null||options.autoClose;function onCreate(err,file){if(err!=null)return cb(err);var offset=new BigInt2(8,options!=null&&options.start||0);function write(buffer,i,cb2){var j=i+constants.MAX_WRITE_LENGTH,chunk=buffer.slice(i,j);request("write",{Buffer:chunk,FileId:file.FileId,Offset:offset.toBuffer()},connection,function(err2){if(err2!=null)return cb2(err2);if(offset=offset.add(chunk.length),j<buffer.length)return write(buffer,j,cb2);cb2()})}var stream=new Writable;if(shouldClose){var close=request.bind(void 0,"close",file,connection);stream._destroy=function(err2,cb2){close(function(err22){if(err22!=null)return cb2(err22);cb2(err2)})},stream._final=close}stream._write=function(chunk,encoding,next){write(Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk,encoding),0,next)},cb(null,stream)}if(isFd)onCreate(null,fd);else request("create",{createDisposition:parseFlags(options!=null&&options.flags||"wx"),path},connection,onCreate)}});var require_writeFile=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint(),constants=require_constants(),parseFlags=require_parse_flags();module.exports=function(filename,data,options,cb){if(typeof options==="function")cb=options,options={};options.encoding=options.encoding||"utf8";var connection=this,file,fileContent=Buffer.isBuffer(data)?data:Buffer.from(data,options.encoding),fileLength=new BigInt2(8,fileContent.length);function createFile(fileCreated){SMB2Request("create",{createDisposition:parseFlags(options!=null&&(options.flags||options.flag)||"wx"),path:filename},connection,function(err,f){if(err)cb&&cb(err);else file=f,fileCreated()})}function closeFile(fileClosed){SMB2Request("close",file,connection,function(err){if(err)cb&&cb(err);else file=null,fileClosed()})}function setFileSize(fileSizeSetted){SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileEndOfFileInformation",Buffer:fileLength.toBuffer()},connection,function(err){if(err)cb&&cb(err);else fileSizeSetted()})}function writeFile(fileWritten){var offset=new BigInt2(8),stop=!1,nbRemainingPackets=0,maxPacketSize=new BigInt2(8,constants.MAX_WRITE_LENGTH);function callback(){return function(err){if(stop)return;if(err)cb&&cb(err),stop=!0;else nbRemainingPackets--,checkDone()}}function checkDone(){if(stop)return;if(createPackets(),nbRemainingPackets===0&&offset.ge(fileLength))fileWritten()}function createPackets(){while(nbRemainingPackets<connection.packetConcurrency&&offset.lt(fileLength)){var rest=fileLength.sub(offset),packetSize=rest.gt(maxPacketSize)?maxPacketSize:rest;SMB2Request("write",{FileId:file.FileId,Offset:offset.toBuffer(),Buffer:fileContent.slice(offset.toNumber(),offset.add(packetSize).toNumber())},connection,callback(offset)),offset=offset.add(packetSize),nbRemainingPackets++}}checkDone()}createFile(function(){setFileSize(function(){writeFile(function(){closeFile(cb)})})})}});var require_unlink=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint(),constants=require_constants();module.exports=function(path,cb){var connection=this;SMB2Request("create",{path,shareAccess:constants.FILE_SHARE_DELETE},connection,function(err,file){if(err)cb&&cb(err);else SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileDispositionInformation",Buffer:new BigInt2(1,1).toBuffer()},connection,function(err2,files){SMB2Request("close",file,connection,function(){if(err2)cb&&cb(err2);else cb&&cb(null,files)})})})}});var require_convert_time=__commonJS((exports,module)=>{var winTicks=1e7,uEpoch=11644473600;module.exports=function(time){var unixTime=time/winTicks-uEpoch;return new Date(unixTime*1000)}});var require_stats=__commonJS((exports,module)=>{var convert=require_convert_time(),BigInt2=require_bigint(),DIRECTORY=require_constants().DIRECTORY;module.exports=function(file){return{birthtime:convert(BigInt2.fromBuffer(file.CreationTime).toNumber()),atime:convert(BigInt2.fromBuffer(file.LastAccessTime).toNumber()),mtime:convert(BigInt2.fromBuffer(file.LastWriteTime).toNumber()),ctime:convert(BigInt2.fromBuffer(file.ChangeTime).toNumber()),size:BigInt2.fromBuffer(file.EndofFile).toNumber(),isDirectory:function(){var attr=file.FileAttributes;if(typeof attr!=="number")attr=BigInt2.fromBuffer(attr).toNumber();return(attr&DIRECTORY)==DIRECTORY}}}});var require_readdir=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,stats=require_stats();module.exports=function(path,options,cb){var connection=this;if(typeof options==="function")cb=options,options={};var mapping=options.stats?function(v){var obj=stats(v);return obj.name=v.Filename,obj}:function(v){return v.Filename};function queryDirectory(filesBatch,file,connection2,cb2){SMB2Request("query_directory",file,connection2,function(err,files){if(err)if(err.code==="STATUS_NO_MORE_FILES")cb2(null,filesBatch);else cb2(err);else filesBatch.push(files.filter(function(v){return v.Filename!=="."&&v.Filename!==".."}).map(mapping)),queryDirectory(filesBatch,file,connection2,cb2)})}function openDirectory(path2,connection2,cb2){SMB2Request("open",{path:path2},connection2,function(err,file){if(err)cb2(err);else return cb2(null,file)})}function closeDirectory(file,connection2,cb2){SMB2Request("close",file,connection2,function(err,res){if(err){if(err.code!=="STATUS_FILE_CLOSED")cb2(err)}cb2(null,res)})}openDirectory(path,connection,function(err,file){var totalFiles=[],filesBatch=[];if(err)cb(err);else queryDirectory(filesBatch,file,connection,function(err2,file2){if(err2)cb(err2);else closeDirectory(file2,connection,function(err3,file3){if(err3)cb(err3);else totalFiles=[].concat(...filesBatch),cb(null,totalFiles)})})})}});var require_rmdir=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint();module.exports=function(path,cb){var connection=this;SMB2Request("open_folder",{path},connection,function(err,file){if(err)cb&&cb(err);else SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileDispositionInformation",Buffer:new BigInt2(1,1).toBuffer()},connection,function(err2,files){SMB2Request("close",file,connection,function(){if(err2)return cb(err2);cb(null,files)})})})}});var require_mkdir=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request;module.exports=function(path,mode,cb){if(typeof mode==="function")cb=mode,mode="0777";var connection=this;SMB2Request("create_folder",{path},connection,function(err,file){if(err)cb&&cb(err);else SMB2Request("close",file,connection,function(){cb&&cb(null)})})}});var require_getSize=__commonJS((exports,module)=>{var BigInt2=require_bigint(),request=require_smb2_forge().request;module.exports=function(path,cb){var connection=this;request("open",{path},connection,function(err,file){if(err!=null)return cb(err);request("close",file,connection,function(){cb(null,BigInt2.fromBuffer(file.EndofFile).toNumber())})})}});var require_stat=__commonJS((exports,module)=>{var stats=require_stats(),request=require_smb2_forge().request;module.exports=function(path,cb){var connection=this;request("open",{path},connection,function(err,file){if(err!=null)return cb(err);request("close",file,connection,function(){cb(null,stats(file))})})}});var require_open=__commonJS((exports,module)=>{var parseFlags=require_parse_flags(),request=require_smb2_forge().request;module.exports=function(path,flags,cb){if(typeof flags==="function")cb=flags,flags=void 0;request("create",{createDisposition:parseFlags(flags||"r"),path},this,cb)}});var require_read=__commonJS((exports,module)=>{var assert=__require("assert"),BigInt2=require_bigint(),request=require_smb2_forge().request,MAX_READ_LENGTH=require_constants().MAX_READ_LENGTH;module.exports=function(file,buffer,offset,length,start,cb){assert(start!==null,"null pos is not supported");var connection=this,end=Math.min(start+length,BigInt2.fromBuffer(file.EndofFile).toNumber()),pos=start;function onRead(err,chunk){if(err!=null)return cb(err,pos-start,buffer);chunk.copy(buffer,offset);var n=chunk.length;offset+=n,pos+=n,readChunk()}function readChunk(){if(pos>=end)return cb(null,pos-start,buffer);request("read",{FileId:file.FileId,Length:Math.min(MAX_READ_LENGTH,end-pos),Offset:new BigInt2(8,pos).toBuffer()},connection,onRead)}process.nextTick(readChunk)}});var require_write=__commonJS((exports,module)=>{var assert=__require("assert"),BigInt2=require_bigint(),request=require_smb2_forge().request,MAX_WRITE_LENGTH=require_constants().MAX_WRITE_LENGTH;module.exports=function(file,buffer,offset,length,start,cb){if(assert(Buffer.isBuffer(buffer)),offset==null)offset=0;else assert.strictEqual(typeof offset,"number"),assert(offset>0),assert(offset<buffer.length);if(length==null)length=buffer.length-offset;else assert.strictEqual(typeof length,"number"),assert(length>0),length=Math.min(length,buffer.length-offset);assert.strictEqual(typeof start,"number");var connection=this,pos=start,chunkLength;function onWrite(err){if(err!=null)return cb(err,pos-start,buffer);length-=chunkLength,offset+=chunkLength,pos+=chunkLength,writeChunk()}function writeChunk(){if(length<=0)return cb(null,pos-start,buffer);chunkLength=Math.min(MAX_WRITE_LENGTH,length),request("write",{Buffer:buffer.slice(offset,offset+chunkLength),FileId:file.FileId,Offset:new BigInt2(8,pos).toBuffer()},connection,onWrite)}process.nextTick(writeChunk)}});var require_close=__commonJS((exports,module)=>{var request=require_smb2_forge().request;module.exports=function(file,cb){request("close",file,this,cb)}});var require_truncate=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint(),FILE_WRITE_DATA=require_constants().FILE_WRITE_DATA;function setFileSize(file,fileLength,connection,cb){SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileEndOfFileInformation",Buffer:fileLength.toBuffer()},connection,cb)}module.exports=function(path,length,cb){var connection=this;SMB2Request("open",{path,desiredAccess:FILE_WRITE_DATA},connection,function(err,file){if(err!=null)return cb(err);setFileSize(file,new BigInt2(8,length),connection,function(err2){SMB2Request("close",file,connection,function(){cb(err2)})})})}});var require_smb2=__commonJS((exports,module)=>{var shareRegExp=/\\\\([^\\]*)\\([^\\]*)\\?/,port=445,packetConcurrency=20,autoCloseTimeout=1e4,autoPromise=require_auto_promise(),SMB2Connection=require_smb2_connection(),SMB=module.exports=function(opt){opt=opt||{};var matches;if(!opt.share||!(matches=opt.share.match(shareRegExp)))throw Error("the share is not valid");if(this.ip=matches[1],this.port=opt.port||port,this.share=matches[2],this.fullPath=opt.share,this.packetConcurrency=opt.packetConcurrency||packetConcurrency,opt.autoCloseTimeout!==void 0)this.autoCloseTimeout=opt.autoCloseTimeout;else this.autoCloseTimeout=autoCloseTimeout;this.domain=opt.domain,this.username=opt.username,this.password=opt.password,this.ProcessId=Buffer.from([Math.floor(Math.random()*256)&255,Math.floor(Math.random()*256)&255,Math.floor(Math.random()*256)&255,Math.floor(Math.random()*256)&254]),this.debug=opt.debug,SMB2Connection.init(this)},proto=SMB.prototype={};proto.disconnect=require_disconnect();proto.exists=autoPromise(SMB2Connection.requireConnect(require_exists()));proto.rename=autoPromise(SMB2Connection.requireConnect(require_rename()));proto.readFile=autoPromise(SMB2Connection.requireConnect(require_readFile()));proto.createReadStream=autoPromise(SMB2Connection.requireConnect(require_createReadStream()));proto.createWriteStream=autoPromise(SMB2Connection.requireConnect(require_createWriteStream()));proto.writeFile=autoPromise(SMB2Connection.requireConnect(require_writeFile()));proto.unlink=autoPromise(SMB2Connection.requireConnect(require_unlink()));proto.readdir=autoPromise(SMB2Connection.requireConnect(require_readdir()));proto.rmdir=autoPromise(SMB2Connection.requireConnect(require_rmdir()));proto.mkdir=autoPromise(SMB2Connection.requireConnect(require_mkdir()));proto.getSize=autoPromise(SMB2Connection.requireConnect(require_getSize()));proto.stat=autoPromise(SMB2Connection.requireConnect(require_stat()));proto.open=autoPromise(SMB2Connection.requireConnect(require_open()));proto.read=autoPromise(require_read(),function(bytesRead,buffer){return{bytesRead,buffer}});proto.write=autoPromise(require_write(),function(bytesWritten,buffer){return{bytesWritten,buffer}});proto.close=autoPromise(require_close());proto.truncate=autoPromise(SMB2Connection.requireConnect(require_truncate()))});import{createHash,randomBytes}from"crypto";var API_KEY_BYTE_LENGTH=32,HASH_ALGORITHM="sha256",generateApiKey=(prefix="nk_live")=>{let randomPart=randomBytes(API_KEY_BYTE_LENGTH).toString("hex"),rawKey=`${prefix}_${randomPart}`,keyHash=hashApiKey(rawKey),keyPreview=`${prefix}_...${randomPart.slice(-4)}`;return{rawKey,keyHash,keyPreview}},hashApiKey=(rawKey)=>{return createHash(HASH_ALGORITHM).update(rawKey).digest("hex")},validateApiKeyFormat=(rawKey)=>{return/^nk_(live|test)_[a-f0-9]{64}$/.test(rawKey)},extractApiKeyFromHeader=(headers)=>{let apiKeyHeader=headers.get("x-api-key");if(apiKeyHeader&&validateApiKeyFormat(apiKeyHeader))return apiKeyHeader;let authHeader=headers.get("authorization");if(authHeader){let bearerMatch=authHeader.match(/^Bearer\s+(nk_(?:live|test)_[a-f0-9]{64})$/);if(bearerMatch?.[1])return bearerMatch[1]}return null},validateApiKeyRecord=(record)=>{if(!record.isActive)return{valid:!1,reason:"API key is inactive"};if(record.revokedAt)return{valid:!1,reason:"API key has been revoked"};if(record.expiresAt&&new Date(record.expiresAt)<new Date)return{valid:!1,reason:"API key has expired"};return{valid:!0,record}},intersectPermissions=(userPermissions,keyPermissions)=>{let userSet=new Set(userPermissions);return keyPermissions.filter((p)=>userSet.has(p))};var init_ApiKey=()=>{};var normalize=(value)=>{return value?.trim().toLowerCase()||"unknown"},extractHeaderValue=(headers,key)=>{return headers[key.toLowerCase()]??headers[key]};import crypto2 from"crypto";var generateDeviceFingerprint=(input)=>{let payload=JSON.stringify({userAgent:normalize(input.userAgent),extra:input.extra??{}});return{hash:crypto2.createHash("sha256").update(payload).digest("base64url"),components:input}};var init_Generate=()=>{};var validateDeviceFingerprint=({savedFingerprint,requestIp,headers})=>{let userAgent=extractHeaderValue(headers,"user-agent"),forwardedFor=extractHeaderValue(headers,"x-forwarded-for")??requestIp??void 0,currentFingerprint=generateDeviceFingerprint({userAgent,ipAddress:forwardedFor}),componentMismatch=[{field:"userAgent",saved:savedFingerprint.components.userAgent,received:userAgent},{field:"ipAddress",saved:savedFingerprint.components.ipAddress,received:forwardedFor}].find(({saved,received})=>saved??(received??"")!=="");if(componentMismatch)return{isValid:!1,reason:`${componentMismatch.field} mismatch`,currentFingerprint};return{isValid:!0,currentFingerprint}};var init_Validate=__esm(()=>{init_Generate()});var init_Fingerprint=__esm(()=>{init_Generate();init_Validate()});import crypto3 from"crypto";var base64UrlEncode=(data)=>{return(Buffer.isBuffer(data)?data.toString("base64"):Buffer.from(data).toString("base64")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},base64UrlDecode=(data)=>{let padding="=".repeat((4-data.length%4)%4),base64=data.replace(/-/g,"+").replace(/_/g,"/")+padding;return Buffer.from(base64,"base64").toString("utf-8")},createSignature=(data,secret,algorithm)=>{let hmacAlgorithm=algorithm.replace("HS","sha"),hmac=crypto3.createHmac(hmacAlgorithm,secret);return hmac.update(data),base64UrlEncode(hmac.digest())},verifySignature=(data,signature,secret,algorithm)=>{let expectedSignature=createSignature(data,secret,algorithm),sigBuf=Buffer.from(signature),expBuf=Buffer.from(expectedSignature);if(sigBuf.length!==expBuf.length)return!1;return crypto3.timingSafeEqual(sigBuf,expBuf)},encodeHeader=(header)=>{return base64UrlEncode(JSON.stringify(header))},encodePayload=(payload)=>{return base64UrlEncode(JSON.stringify(payload))},decodeHeader=(encoded)=>{try{return JSON.parse(base64UrlDecode(encoded))}catch{return null}},decodePayload=(encoded)=>{try{return JSON.parse(base64UrlDecode(encoded))}catch{return null}};var init_utils2=()=>{};var decodeJWT=(token)=>{let parts=token.split(".");if(parts.length!==3)return null;let[encodedHeader,encodedPayload,signature]=parts;if(!encodedHeader||!encodedPayload||!signature)return null;let header=decodeHeader(encodedHeader),payload=decodePayload(encodedPayload);if(!header||!payload)return null;return{header,payload,signature}};var init_Decode=__esm(()=>{init_utils2()});import{randomUUID}from"crypto";var signJWT=(options,secret,algorithm="HS256")=>{let header={alg:algorithm,typ:"JWT"},now=Math.floor(Date.now()/1000),payload={sub:options.subject,iat:now,...options.expiresInSeconds===null?{}:{exp:now+options.expiresInSeconds},iss:options.issuer,aud:options.audience,jti:options.jwtId||randomUUID(),sessionId:options.sessionId,...options.customClaims},encodedHeader=encodeHeader(header),encodedPayload=encodePayload(payload),dataToSign=`${encodedHeader}.${encodedPayload}`,signature=createSignature(dataToSign,secret,algorithm);return`${dataToSign}.${signature}`};var init_Sign=__esm(()=>{init_utils2()});var audienceMatches=(aud,expected)=>{if(typeof aud==="string")return aud===expected;if(Array.isArray(aud))return aud.includes(expected);return!1},verifyJWT=(token,secret,expected)=>{let parts=token.split(".");if(parts.length!==3)return{valid:!1,error:"Invalid token format: expected 3 parts"};let[encodedHeader,encodedPayload,signature]=parts;if(!encodedHeader||!encodedPayload||!signature)return{valid:!1,error:"Invalid token format: missing parts"};let header=decodeHeader(encodedHeader);if(!header)return{valid:!1,error:"Invalid header: failed to decode"};if(header.typ!=="JWT")return{valid:!1,error:"Invalid header: typ must be JWT"};if(!["HS256","HS384","HS512"].includes(header.alg))return{valid:!1,error:`Unsupported algorithm: ${header.alg}`};let dataToVerify=`${encodedHeader}.${encodedPayload}`;if(!verifySignature(dataToVerify,signature,secret,header.alg))return{valid:!1,error:"Invalid signature"};let payload=decodePayload(encodedPayload);if(!payload)return{valid:!1,error:"Invalid payload: failed to decode"};let now=Math.floor(Date.now()/1000);if(payload.exp&&payload.exp<now)return{valid:!1,error:"Token expired"};if(payload.iat&&payload.iat>now+60)return{valid:!1,error:"Token issued in the future"};if(expected?.issuer&&payload.iss!==expected.issuer)return{valid:!1,error:"Invalid issuer"};if(expected?.audience&&!audienceMatches(payload.aud,expected.audience))return{valid:!1,error:"Invalid audience"};return{valid:!0,payload}};var init_Verify=__esm(()=>{init_utils2()});var exports_JWT={};__export(exports_JWT,{verifyJWT:()=>verifyJWT,signJWT:()=>signJWT,decodeJWT:()=>decodeJWT});var init_JWT=__esm(()=>{init_Decode();init_Sign();init_Verify()});var init_Generate2=()=>{};var init_Password=__esm(()=>{init_Generate2()});var init_Logger2=__esm(()=>{init_auditTaxonomy();init_Logger();init_ServerLogBuffer();init_transports();init_utils();init_scopes()});var DEFAULT_DAPR_HOST="127.0.0.1",DEFAULT_DAPR_PORT="3500",DEFAULT_MAX_BODY_SIZE_MB=4,DEFAULT_STATE_STORE="statestore-redis",DEFAULT_PUBSUB_NAME="pubsub-rabbitmq",DEFAULT_SECRET_STORE="secretstore",DEFAULT_CONFIG_STORE="configstore-redis",ENV_DAPR_HOST="DAPR_HOST",ENV_DAPR_HTTP_PORT="DAPR_HTTP_PORT",ENV_DAPR_HTTP_ENDPOINT="DAPR_HTTP_ENDPOINT",ENV_DAPR_GRPC_ENDPOINT="DAPR_GRPC_ENDPOINT",ENV_DAPR_API_TOKEN="DAPR_API_TOKEN",DEFAULT_OPERATION_TIMEOUT_MS=30000,DEFAULT_CONNECTION_TIMEOUT_MS=1e4,DEFAULT_HEALTH_CHECK_TIMEOUT_MS=5000,CONNECTION_STATUS,HEALTH_STATUS,ERROR_CODES;var init_constants=__esm(()=>{CONNECTION_STATUS={CONNECTED:"connected",DISCONNECTED:"disconnected",CONNECTING:"connecting",ERROR:"error"},HEALTH_STATUS={HEALTHY:"healthy",UNHEALTHY:"unhealthy"},ERROR_CODES={CONNECTION_ERROR:"DAPR_CONNECTION_ERROR",TIMEOUT_ERROR:"DAPR_TIMEOUT_ERROR",STATE_ERROR:"DAPR_STATE_ERROR",PUBSUB_ERROR:"DAPR_PUBSUB_ERROR",BINDING_ERROR:"DAPR_BINDING_ERROR",SECRET_ERROR:"DAPR_SECRET_ERROR",CONFIG_ERROR:"DAPR_CONFIG_ERROR",INVOKE_ERROR:"DAPR_INVOKE_ERROR",CRYPTO_ERROR:"DAPR_CRYPTO_ERROR",LOCK_ERROR:"DAPR_LOCK_ERROR",WORKFLOW_ERROR:"DAPR_WORKFLOW_ERROR",VALIDATION_ERROR:"DAPR_VALIDATION_ERROR"}});var DaprManagerError,createConnectionError=(message,details)=>new DaprManagerError(ERROR_CODES.CONNECTION_ERROR,message,details),createTimeoutError=(message,details)=>new DaprManagerError(ERROR_CODES.TIMEOUT_ERROR,message,details),createStateError=(message,details)=>new DaprManagerError(ERROR_CODES.STATE_ERROR,message,details),createPubSubError=(message,details)=>new DaprManagerError(ERROR_CODES.PUBSUB_ERROR,message,details),createBindingError=(message,details)=>new DaprManagerError(ERROR_CODES.BINDING_ERROR,message,details),createSecretError=(message,details)=>new DaprManagerError(ERROR_CODES.SECRET_ERROR,message,details),createConfigError=(message,details)=>new DaprManagerError(ERROR_CODES.CONFIG_ERROR,message,details),createInvokeError=(message,details)=>new DaprManagerError(ERROR_CODES.INVOKE_ERROR,message,details),createCryptoError=(message,details)=>new DaprManagerError(ERROR_CODES.CRYPTO_ERROR,message,details),createLockError=(message,details)=>new DaprManagerError(ERROR_CODES.LOCK_ERROR,message,details),createWorkflowError=(message,details)=>new DaprManagerError(ERROR_CODES.WORKFLOW_ERROR,message,details),safeExecute=async(operation,errorCreator)=>{try{return await operation()}catch(error){let errorMessage=error instanceof Error?error.message:String(error);throw errorCreator(errorMessage,error)}};var init_error_handling=__esm(()=>{init_constants();DaprManagerError=class DaprManagerError extends Error{code;details;constructor(code,message,details){super(message);this.name="DaprManagerError",this.code=code,this.details=details}toJSON(){return{code:this.code,message:this.message,details:this.details}}}});var LOG_LEVEL_PRIORITY2,createDefaultLogger=(minLevel="info")=>{let minPriority=LOG_LEVEL_PRIORITY2[minLevel],scoped=logger.scoped("dapr.client"),logWithLevel=(level)=>(message,...meta)=>{if(LOG_LEVEL_PRIORITY2[level]<minPriority)return;let context=meta.length>0?{meta}:void 0;if(level==="error")scoped.error(message,void 0,context);else scoped[level](message,context)};return{debug:logWithLevel("debug"),info:logWithLevel("info"),warn:logWithLevel("warn"),error:logWithLevel("error")}},withTimeout=async(fn,timeoutMs,errorMessage="Operation timed out")=>{return Promise.race([fn(),new Promise((_,reject)=>{setTimeout(()=>{reject(createTimeoutError(errorMessage))},timeoutMs)})])},validateRequired=(params,requiredKeys,entityName)=>{let missingKeys=requiredKeys.filter((key)=>params[key]===void 0);if(missingKeys.length>0)throw Error(`Missing required ${entityName} parameters: ${missingKeys.join(", ")}`)};var init_utils3=__esm(()=>{init_Logger2();init_constants();init_error_handling();LOG_LEVEL_PRIORITY2={debug:0,info:1,warn:2,error:3}});class DaprBindingClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async invoke(name,operation,data,options={}){return validateRequired({name,operation},["name","operation"],"binding invoke"),safeExecute(async()=>{this.logger.debug("Invoking binding",{name,operation});let response=await(await this.client()).binding.send(name,operation,data,options.metadata);return this.logger.debug("Binding invoked successfully",{name,operation}),response},(message,details)=>createBindingError(`Failed to invoke binding ${name}: ${message}`,details))}}var init_binding_client=__esm(()=>{init_error_handling();init_utils3()});class DaprConfigClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async get(keys,storeName=DEFAULT_CONFIG_STORE){if(validateRequired({keys,storeName},["keys","storeName"],"config get"),keys.length===0)return{};return safeExecute(async()=>{this.logger.debug("Getting configuration",{keys,storeName});let response=await(await this.client()).configuration.get(storeName,keys);return this.logger.debug("Configuration retrieved",{keys,storeName,itemCount:Object.keys(response.items||{}).length}),response.items||{}},(message,details)=>createConfigError(`Failed to get configuration: ${message}`,details))}async subscribeWithKeys(keys,callback,storeName=DEFAULT_CONFIG_STORE){if(validateRequired({keys,callback,storeName},["keys","callback","storeName"],"config subscribeWithKeys"),keys.length===0)throw createConfigError("At least one key must be provided for subscription");return safeExecute(async()=>{this.logger.debug("Subscribing to configuration updates",{keys,storeName});let stream=await(await this.client()).configuration.subscribeWithKeys(storeName,keys,async(data)=>{try{this.logger.debug("Received configuration update",{storeName,updatedKeys:Object.keys(data.items||{})}),await callback(data)}catch(error){this.logger.error("Error in configuration subscription callback",error)}});return this.logger.debug("Configuration subscription established",{keys,storeName}),{stop:()=>{this.logger.debug("Stopping configuration subscription",{keys,storeName}),stream.stop()}}},(message,details)=>createConfigError(`Failed to subscribe to configuration updates: ${message}`,details))}async getValue(key,storeName=DEFAULT_CONFIG_STORE){return(await this.get([key],storeName))[key]?.value}async getValues(keys,storeName=DEFAULT_CONFIG_STORE){let items=await this.get(keys,storeName),values={};for(let key in items)if(items[key]?.value!==void 0)values[key]=items[key].value;return values}}var init_config_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprCryptoClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async encrypt(data,options){return validateRequired({data,componentName:options.componentName},["data","componentName"],"crypto encrypt"),safeExecute(async()=>{this.logger.debug("Encrypting data",{componentName:options.componentName,keyName:options.keyName,keyWrapAlgorithm:options.keyWrapAlgorithm});let client=await this.client(),inputData=typeof data==="string"?Buffer.from(data):data,cryptoOptions={componentName:options.componentName};if(options.keyName)cryptoOptions.keyName=options.keyName;if(options.keyWrapAlgorithm)cryptoOptions.keyWrapAlgorithm=options.keyWrapAlgorithm;let encryptedData=await client.crypto.encrypt(inputData,cryptoOptions);return this.logger.debug("Data encrypted successfully",{componentName:options.componentName,inputSize:inputData.length,outputSize:encryptedData.length}),encryptedData},(message,details)=>createCryptoError(`Failed to encrypt data: ${message}`,details))}async decrypt(data,options){return validateRequired({data,componentName:options.componentName},["data","componentName"],"crypto decrypt"),safeExecute(async()=>{this.logger.debug("Decrypting data",{componentName:options.componentName});let client=await this.client(),inputData=typeof data==="string"?Buffer.from(data):data,cryptoOptions={componentName:options.componentName};if(options.keyName)cryptoOptions.keyName=options.keyName;if(options.keyWrapAlgorithm)cryptoOptions.keyWrapAlgorithm=options.keyWrapAlgorithm;let decryptedData=await client.crypto.decrypt(inputData,cryptoOptions);return this.logger.debug("Data decrypted successfully",{componentName:options.componentName,inputSize:inputData.length,outputSize:decryptedData.length}),decryptedData},(message,details)=>createCryptoError(`Failed to decrypt data: ${message}`,details))}async encryptString(plaintext,options){return(await this.encrypt(plaintext,options)).toString("base64")}async decryptString(ciphertext,options){let encryptedBuffer=Buffer.from(ciphertext,"base64");return(await this.decrypt(encryptedBuffer,options)).toString("utf-8")}}var init_crypto_client=__esm(()=>{init_error_handling();init_utils3()});function dapr(){if(!cachedDapr)cachedDapr=__require("@dapr/dapr");return cachedDapr}class DaprInvokeClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async invoke(appId,methodName,httpMethod,data,options={}){httpMethod??=dapr().HttpMethod.POST,validateRequired({appId,methodName,httpMethod},["appId","methodName","httpMethod"],"invoke service");let timeoutMs=options.timeout||DEFAULT_OPERATION_TIMEOUT_MS;return safeExecute(async()=>{this.logger.debug("Invoking service",{appId,methodName,httpMethod,hasData:data!==void 0});let fullMethodName=methodName;if(options.queryParams&&Object.keys(options.queryParams).length>0){let queryString=Object.entries(options.queryParams).map(([key,value])=>`${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");fullMethodName=`${methodName}?${queryString}`}let client=await this.client(),response=await withTimeout(()=>client.invoker.invoke(appId,fullMethodName,httpMethod,data,options.headers),timeoutMs,`Service invocation timed out after ${timeoutMs}ms`);if(this.logger.debug("Service invoked successfully",{appId,methodName,httpMethod,status:response?.status}),!response)return;if("data"in response)return response.data;return response},(message,details)=>createInvokeError(`Failed to invoke service ${appId}.${methodName}: ${message}`,details))}async get(appId,methodName,options={}){return this.invoke(appId,methodName,dapr().HttpMethod.GET,void 0,options)}async post(appId,methodName,data,options={}){return this.invoke(appId,methodName,dapr().HttpMethod.POST,data,options)}async put(appId,methodName,data,options={}){return this.invoke(appId,methodName,dapr().HttpMethod.PUT,data,options)}async delete(appId,methodName,options={}){return this.invoke(appId,methodName,dapr().HttpMethod.DELETE,void 0,options)}}var cachedDapr=null;var init_invoke_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprLockClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async lock(storeName,resourceId,lockOwner,options){return validateRequired({storeName,resourceId,lockOwner,expiryInSeconds:options.expiryInSeconds},["storeName","resourceId","lockOwner","expiryInSeconds"],"lock"),safeExecute(async()=>{this.logger.debug("Acquiring lock",{storeName,resourceId,lockOwner});let response=await(await this.client()).lock.lock(storeName,resourceId,lockOwner,options.expiryInSeconds);return this.logger.debug("Lock acquisition result",{storeName,resourceId,lockOwner,success:response.success}),{success:response.success}},(message,details)=>createLockError(`Failed to acquire lock for resource ${resourceId}: ${message}`,details))}async unlock(storeName,resourceId,lockOwner){return validateRequired({storeName,resourceId,lockOwner},["storeName","resourceId","lockOwner"],"unlock"),safeExecute(async()=>{this.logger.debug("Releasing lock",{storeName,resourceId,lockOwner});let response=await(await this.client()).lock.unlock(storeName,resourceId,lockOwner);return this.logger.debug("Lock release result",{storeName,resourceId,lockOwner,status:this.getLockStatusName(response.status)}),{status:response.status}},(message,details)=>createLockError(`Failed to release lock for resource ${resourceId}: ${message}`,details))}getLockStatusName(status){switch(status){case 0:return"Success";case 1:return"LockDoesNotExist";case 2:return"LockBelongsToOthers";default:return"InternalError"}}}var init_lock_client=__esm(()=>{init_error_handling();init_utils3()});class DaprPubSubClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async publish(topic,data,options={},pubsubName=DEFAULT_PUBSUB_NAME){return validateRequired({topic,data,pubsubName},["topic","data","pubsubName"],"pubsub publish"),safeExecute(async()=>{this.logger.debug("Publishing message to topic",{topic,pubsubName}),await(await this.client()).pubsub.publish(pubsubName,topic,data,{metadata:options.metadata,contentType:options.contentType}),this.logger.debug("Message published successfully",{topic,pubsubName})},(message,details)=>createPubSubError(`Failed to publish message to topic ${topic}: ${message}`,details))}async publishBulk(topic,messages,pubsubName=DEFAULT_PUBSUB_NAME){if(validateRequired({topic,messages,pubsubName},["topic","messages","pubsubName"],"pubsub publishBulk"),messages.length===0)return{failedEntries:[]};return safeExecute(async()=>{this.logger.debug("Publishing bulk messages to topic",{topic,pubsubName,messageCount:messages.length});let client=await this.client(),daprMessages=messages.map((msg)=>{if(typeof msg==="object"&&"event"in msg)return{entryID:msg.entryId,event:msg.event,contentType:msg.contentType,metadata:msg.metadata};return{event:msg}}),response=await client.pubsub.publishBulk(pubsubName,topic,daprMessages),failedCount=response.failedMessages?.length||0;if(failedCount>0)this.logger.warn("Some messages failed to publish",{topic,pubsubName,failedCount,totalCount:messages.length});else this.logger.debug("All bulk messages published successfully",{topic,pubsubName,messageCount:messages.length});return{failedEntries:(response.failedMessages||[]).map((failed)=>({entryId:failed.message.entryID||"",error:failed.error?.message||"Unknown error"}))}},(message,details)=>createPubSubError(`Failed to publish bulk messages to topic ${topic}: ${message}`,details))}createBulkPublishMessage(event,entryId,contentType,metadata){return{entryId,event,contentType,metadata}}}var init_pubsub_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprSecretClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async get(key,options={},storeName=DEFAULT_SECRET_STORE){return validateRequired({key,storeName},["key","storeName"],"secret get"),safeExecute(async()=>{this.logger.debug("Getting secret",{key,storeName});let client=await this.client(),metadataStr=options.metadata?JSON.stringify(options.metadata):void 0,result=await client.secret.get(storeName,key,metadataStr);return this.logger.debug("Secret retrieved",{key,storeName}),result},(message,details)=>createSecretError(`Failed to get secret ${key}: ${message}`,details))}async getBulk(_options={},storeName=DEFAULT_SECRET_STORE){return validateRequired({storeName},["storeName"],"secret getBulk"),safeExecute(async()=>{this.logger.debug("Getting all secrets",{storeName});let result=await(await this.client()).secret.getBulk(storeName);return this.logger.debug("All secrets retrieved",{storeName,secretCount:Object.keys(result).length}),result},(message,details)=>createSecretError(`Failed to get all secrets: ${message}`,details))}}var init_secret_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprStateClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async save(stateItems,options={},storeName=DEFAULT_STATE_STORE){if(validateRequired({stateItems,storeName},["stateItems","storeName"],"state save"),stateItems.length===0)return;return safeExecute(async()=>{this.logger.debug("Saving state items",{count:stateItems.length,storeName}),await(await this.client()).state.save(storeName,stateItems,options),this.logger.debug("State items saved successfully",{count:stateItems.length,storeName})},(message,details)=>createStateError(`Failed to save state items: ${message}`,details))}async get(key,storeName=DEFAULT_STATE_STORE){return validateRequired({key,storeName},["key","storeName"],"state get"),safeExecute(async()=>{this.logger.debug("Getting state item",{key,storeName});let result=await(await this.client()).state.get(storeName,key);if(this.logger.debug("State item retrieved",{key,storeName,found:result!==void 0}),result===void 0||result===null)return;if(typeof result==="string")try{return JSON.parse(result)}catch{return result}if(typeof result==="object")return result;return result},(message,details)=>createStateError(`Failed to get state item ${key}: ${message}`,details))}async getBulk(keys,storeName=DEFAULT_STATE_STORE){if(validateRequired({keys,storeName},["keys","storeName"],"state getBulk"),keys.length===0)return{};return safeExecute(async()=>{this.logger.debug("Getting bulk state items",{count:keys.length,storeName});let results=await(await this.client()).state.getBulk(storeName,keys),resultMap={};return results.forEach((item)=>{if(item.data!==void 0)resultMap[item.key]=item.data}),this.logger.debug("Bulk state items retrieved",{count:keys.length,found:Object.keys(resultMap).length,storeName}),resultMap},(message,details)=>createStateError(`Failed to get bulk state items: ${message}`,details))}async delete(key,etag,metadata,storeName=DEFAULT_STATE_STORE){return validateRequired({key,storeName},["key","storeName"],"state delete"),safeExecute(async()=>{this.logger.debug("Deleting state item",{key,storeName});let client=await this.client(),options={};if(etag)options.etag=etag;if(metadata)options.metadata=metadata;await client.state.delete(storeName,key,options),this.logger.debug("State item deleted",{key,storeName})},(message,details)=>createStateError(`Failed to delete state item ${key}: ${message}`,details))}async transaction(operations,storeName=DEFAULT_STATE_STORE){if(validateRequired({operations,storeName},["operations","storeName"],"state transaction"),operations.length===0)return;return safeExecute(async()=>{this.logger.debug("Executing state transaction",{operationCount:operations.length,storeName});let client=await this.client(),daprOperations=operations.map((op)=>({operation:op.operation,request:{key:op.request.key,value:op.request.value,etag:op.request.etag?{value:op.request.etag}:void 0,metadata:op.request.metadata}}));await client.state.transaction(storeName,daprOperations),this.logger.debug("State transaction executed successfully",{operationCount:operations.length,storeName})},(message,details)=>createStateError(`Failed to execute state transaction: ${message}`,details))}async query(query,storeName=DEFAULT_STATE_STORE){return validateRequired({query,storeName},["query","storeName"],"state query"),safeExecute(async()=>{this.logger.debug("Querying state store",{storeName});let result=await(await this.client()).state.query(storeName,query);return this.logger.debug("State query executed",{storeName,resultCount:result.results?.length||0}),(result.results||[]).map((item)=>item.data)},(message,details)=>createStateError(`Failed to query state store: ${message}`,details))}async saveItem(key,value,options={},storeName=DEFAULT_STATE_STORE){let stateItem={key,value};return this.save([stateItem],options,storeName)}async upsert(key,value,options={},storeName=DEFAULT_STATE_STORE){return this.saveItem(key,value,options,storeName)}}var init_state_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprWorkflowClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async start(workflowName,input,options={}){return validateRequired({workflowName},["workflowName"],"workflow start"),safeExecute(async()=>{this.logger.debug("Starting workflow",{workflowName,instanceId:options.instanceId||"auto-generated",workflowComponent:options.workflowComponent});let instanceId=await(await this.client()).workflow.start(workflowName,input,options.instanceId);return this.logger.debug("Workflow started",{workflowName,instanceId}),instanceId},(message,details)=>createWorkflowError(`Failed to start workflow ${workflowName}: ${message}`,details))}async get(instanceId){return validateRequired({instanceId},["instanceId"],"workflow get"),safeExecute(async()=>{this.logger.debug("Getting workflow instance",{instanceId});let instance=await(await this.client()).workflow.get(instanceId);return this.logger.debug("Workflow instance retrieved",{instanceId,workflowName:instance.workflowName,runtimeStatus:instance.runtimeStatus}),{instanceId:instance.instanceID,workflowName:instance.workflowName,createdAt:new Date(instance.createdAt),lastUpdatedAt:new Date(instance.lastUpdatedAt),runtimeStatus:instance.runtimeStatus,properties:instance.properties||{}}},(message,details)=>createWorkflowError(`Failed to get workflow instance ${instanceId}: ${message}`,details))}async terminate(instanceId){return validateRequired({instanceId},["instanceId"],"workflow terminate"),safeExecute(async()=>{this.logger.debug("Terminating workflow instance",{instanceId}),await(await this.client()).workflow.terminate(instanceId),this.logger.debug("Workflow instance terminated",{instanceId})},(message,details)=>createWorkflowError(`Failed to terminate workflow instance ${instanceId}: ${message}`,details))}async pause(instanceId){return validateRequired({instanceId},["instanceId"],"workflow pause"),safeExecute(async()=>{this.logger.debug("Pausing workflow instance",{instanceId}),await(await this.client()).workflow.pause(instanceId),this.logger.debug("Workflow instance paused",{instanceId})},(message,details)=>createWorkflowError(`Failed to pause workflow instance ${instanceId}: ${message}`,details))}async resume(instanceId){return validateRequired({instanceId},["instanceId"],"workflow resume"),safeExecute(async()=>{this.logger.debug("Resuming workflow instance",{instanceId}),await(await this.client()).workflow.resume(instanceId),this.logger.debug("Workflow instance resumed",{instanceId})},(message,details)=>createWorkflowError(`Failed to resume workflow instance ${instanceId}: ${message}`,details))}async purge(instanceId){return validateRequired({instanceId},["instanceId"],"workflow purge"),safeExecute(async()=>{this.logger.debug("Purging workflow instance",{instanceId}),await(await this.client()).workflow.purge(instanceId),this.logger.debug("Workflow instance purged",{instanceId})},(message,details)=>createWorkflowError(`Failed to purge workflow instance ${instanceId}: ${message}`,details))}async raiseEvent(instanceId,eventName,eventData){return validateRequired({instanceId,eventName},["instanceId","eventName"],"workflow raiseEvent"),safeExecute(async()=>{this.logger.debug("Raising event for workflow instance",{instanceId,eventName}),await(await this.client()).workflow.raise(instanceId,eventName,eventData),this.logger.debug("Event raised for workflow instance",{instanceId,eventName})},(message,details)=>createWorkflowError(`Failed to raise event ${eventName} for workflow instance ${instanceId}: ${message}`,details))}}var init_workflow_client=__esm(()=>{init_error_handling();init_utils3()});function dapr2(){if(!cachedDapr2)cachedDapr2=__require("@dapr/dapr");return cachedDapr2}class DaprConnectionManager{client=null;daprHost;daprPort;communicationProtocolOption;maxBodySizeMb;daprApiToken;logger;connectionStatus=CONNECTION_STATUS.DISCONNECTED;connectionPromise=null;constructor(options={}){this.daprHost=options.daprHost||process.env[ENV_DAPR_HOST]||DEFAULT_DAPR_HOST,this.daprPort=options.daprPort||process.env[ENV_DAPR_HTTP_PORT]||DEFAULT_DAPR_PORT,this.communicationProtocolOption=options.communicationProtocol,this.maxBodySizeMb=options.maxBodySizeMb||DEFAULT_MAX_BODY_SIZE_MB,this.daprApiToken=options.daprApiToken||process.env[ENV_DAPR_API_TOKEN],this.logger=options.logger||createDefaultLogger(),this.logger.info("DaprConnectionManager initialized",{daprHost:this.daprHost,daprPort:this.daprPort,communicationProtocol:this.communicationProtocolOption??"default (HTTP)"})}get communicationProtocol(){return this.communicationProtocolOption??dapr2().CommunicationProtocolEnum.HTTP}async getClient(){if(!this.client||this.connectionStatus!==CONNECTION_STATUS.CONNECTED)await this.connect();if(!this.client)throw createConnectionError("Not connected to Dapr sidecar");return this.client}async connect(){if(this.connectionPromise)return this.connectionPromise;if(this.client&&this.connectionStatus===CONNECTION_STATUS.CONNECTED)return Promise.resolve();this.connectionStatus=CONNECTION_STATUS.CONNECTING,this.connectionPromise=this.establishConnection();try{await this.connectionPromise,this.connectionStatus=CONNECTION_STATUS.CONNECTED}catch(error){throw this.connectionStatus=CONNECTION_STATUS.ERROR,error}finally{this.connectionPromise=null}}async establishConnection(){try{this.logger.info("Connecting to Dapr sidecar",{daprHost:this.daprHost,daprPort:this.daprPort,protocol:this.communicationProtocol});let protocols=dapr2().CommunicationProtocolEnum,useEndpointFromEnv=process.env[ENV_DAPR_HTTP_ENDPOINT]&&this.communicationProtocol===protocols.HTTP||process.env[ENV_DAPR_GRPC_ENDPOINT]&&this.communicationProtocol===protocols.GRPC,clientOptions={communicationProtocol:this.communicationProtocol,maxBodySizeMb:this.maxBodySizeMb,logger:{level:dapr2().LogLevel.Warn}};if(!useEndpointFromEnv)clientOptions.daprHost=this.daprHost,clientOptions.daprPort=this.daprPort;if(this.daprApiToken)clientOptions.daprApiToken=this.daprApiToken;await withTimeout(async()=>{this.client=new(dapr2()).DaprClient(clientOptions)},DEFAULT_CONNECTION_TIMEOUT_MS,"Connection to Dapr sidecar timed out"),await this.healthCheck(),this.logger.info("Successfully connected to Dapr sidecar")}catch(error){throw this.logger.error("Failed to connect to Dapr sidecar",error),this.client=null,createConnectionError(`Failed to connect to Dapr sidecar at ${this.daprHost}:${this.daprPort}`,error)}}async disconnect(){if(!this.client)return;try{this.logger.info("Disconnecting from Dapr sidecar"),this.client=null,this.connectionStatus=CONNECTION_STATUS.DISCONNECTED,this.logger.info("Disconnected from Dapr sidecar")}catch(error){throw this.logger.error("Error during disconnect",error),createConnectionError("Failed to disconnect from Dapr sidecar",error)}}isConnected(){return this.client!==null&&this.connectionStatus===CONNECTION_STATUS.CONNECTED}getConnectionStatus(){return this.connectionStatus}async healthCheck(){if(!this.client)throw createConnectionError("Not connected to Dapr sidecar");try{return await withTimeout(async()=>{if(!this.client)throw createConnectionError("Not connected to Dapr sidecar");let response=await this.client.invoker.invoke("healthz","healthz",dapr2().HttpMethod.GET);return{status:response.status===204?HEALTH_STATUS.HEALTHY:HEALTH_STATUS.UNHEALTHY,version:response.headers?.["dapr-version"]||"unknown"}},DEFAULT_HEALTH_CHECK_TIMEOUT_MS,"Health check timed out")}catch(error){return this.logger.error("Health check failed",error),{status:HEALTH_STATUS.UNHEALTHY,version:"unknown"}}}getClientConfig(){return{daprHost:this.daprHost,daprPort:this.daprPort,communicationProtocol:this.communicationProtocol,maxBodySizeMb:this.maxBodySizeMb,hasApiToken:!!this.daprApiToken,connectionStatus:this.connectionStatus}}}var cachedDapr2=null;var init_connection_manager=__esm(()=>{init_constants();init_error_handling();init_utils3()});var init_types2=()=>{};class DaprManager{connectionManager;logger;_state;_pubsub;_binding;_secret;_config;_invoke;_lock;_crypto;_workflow;constructor(options={}){this.logger=options.logger||createDefaultLogger(),this.connectionManager=new DaprConnectionManager(options);let clientProvider=async()=>{return this.connectionManager.getClient()};this._state=new DaprStateClient(clientProvider,this.logger),this._pubsub=new DaprPubSubClient(clientProvider,this.logger),this._binding=new DaprBindingClient(clientProvider,this.logger),this._secret=new DaprSecretClient(clientProvider,this.logger),this._config=new DaprConfigClient(clientProvider,this.logger),this._invoke=new DaprInvokeClient(clientProvider,this.logger),this._lock=new DaprLockClient(clientProvider,this.logger),this._crypto=new DaprCryptoClient(clientProvider,this.logger),this._workflow=new DaprWorkflowClient(clientProvider,this.logger)}async connect(){await this.connectionManager.connect()}async disconnect(){await this.connectionManager.disconnect()}isConnected(){return this.connectionManager.isConnected()}getConnectionStatus(){return this.connectionManager.getConnectionStatus()}async healthCheck(){return this.connectionManager.healthCheck()}getClientConfig(){return this.connectionManager.getClientConfig()}get state(){return this._state}get pubsub(){return this._pubsub}get binding(){return this._binding}get secret(){return this._secret}get config(){return this._config}get invoke(){return this._invoke}get lock(){return this._lock}get crypto(){return this._crypto}get workflow(){return this._workflow}}function getDaprManager(){if(!daprManagerInstance)daprManagerInstance=new DaprManager;return daprManagerInstance}var daprManagerInstance=null,daprManager;var init_Dapr=__esm(()=>{init_binding_client();init_config_client();init_crypto_client();init_invoke_client();init_lock_client();init_pubsub_client();init_secret_client();init_state_client();init_workflow_client();init_connection_manager();init_utils3();init_binding_client();init_config_client();init_crypto_client();init_invoke_client();init_lock_client();init_pubsub_client();init_secret_client();init_state_client();init_workflow_client();init_constants();init_error_handling();init_types2();daprManager=new Proxy({},{get(_target,property,receiver){let value=Reflect.get(getDaprManager(),property,receiver);return typeof value==="function"?value.bind(getDaprManager()):value},has(_target,property){return property in getDaprManager()}})});import Redis from"ioredis";class DirectRedisStore{client;constructor(client){this.client=client}async create(key,value,ttlSeconds){try{return{success:!0,data:ttlSeconds?await this.client.set(key,JSON.stringify(value),"EX",ttlSeconds):await this.client.set(key,JSON.stringify(value))}}catch(error){return{success:!1,error:error.message}}}async read(key){try{let raw=await this.client.get(key);return{success:!0,data:raw?JSON.parse(raw):null}}catch(error){return{success:!1,error:error.message}}}async update(key,value,preserveTtl=!0){try{return{success:!0,data:preserveTtl?await this.client.set(key,JSON.stringify(value),"KEEPTTL"):await this.client.set(key,JSON.stringify(value))}}catch(error){return{success:!1,error:error.message}}}async remove(key){try{return{success:!0,data:await this.client.del(key)}}catch(error){return{success:!1,error:error.message}}}async exists(key){try{return{success:!0,data:await this.client.exists(key)===1}}catch(error){return{success:!1,error:error.message}}}getClient(){return this.client}}class DaprRedisStore{storeName;keyPrefix;dapr;constructor(storeName,keyPrefix=""){this.storeName=storeName;this.keyPrefix=keyPrefix;this.dapr=new DaprManager}k(key){return this.keyPrefix+key}async create(key,value,ttlSeconds){try{let metadata=ttlSeconds?{ttlInSeconds:String(ttlSeconds)}:void 0;return await this.dapr.state.save([{key:this.k(key),value,metadata}],void 0,this.storeName),{success:!0,data:"OK"}}catch(error){return{success:!1,error:error.message}}}async read(key){try{return{success:!0,data:await this.dapr.state.get(this.k(key),this.storeName)??null}}catch(error){return{success:!1,error:error.message}}}async update(key,value,_preserveTtl=!0){try{return await this.dapr.state.save([{key:this.k(key),value}],void 0,this.storeName),{success:!0,data:"OK"}}catch(error){return{success:!1,error:error.message}}}async remove(key){try{return await this.dapr.state.delete(this.k(key),void 0,void 0,this.storeName),{success:!0,data:1}}catch(error){return{success:!1,error:error.message}}}async exists(key){try{let data=await this.dapr.state.get(this.k(key),this.storeName);return{success:!0,data:data!==void 0&&data!==null}}catch(error){return{success:!1,error:error.message}}}}class RedisManager{static instance=null;store;directClient=null;useDapr;constructor(config){if(RedisManager.instance){this.store=RedisManager.instance.store,this.directClient=RedisManager.instance.directClient,this.useDapr=RedisManager.instance.useDapr;return}if(!config)throw Error("Redis config must be provided for first initialization.");assertRedisConfig(config),this.useDapr=config.withDapr??!1;let keyPrefix=config.keyPrefix||"";if(config.withDapr)this.store=new DaprRedisStore(config.stateStoreName??"statestore",keyPrefix);else{let client=config.url?new Redis(config.url,keyPrefix?{keyPrefix}:{}):new Redis({host:config.host,port:config.port,...config.password?{password:config.password}:{},...config.username?{username:config.username}:{},...config.tls?{tls:{}}:{},...keyPrefix?{keyPrefix}:{}});this.directClient=client,this.store=new DirectRedisStore(client)}RedisManager.instance=this}static async reset(){let current=RedisManager.instance;if(RedisManager.instance=null,!current?.directClient)return;try{await current.directClient.quit()}catch{}}async create(key,value,ttlSeconds){return this.store.create(key,value,ttlSeconds)}async read(key){return this.store.read(key)}async update(key,value,preserveTtl=!0){return this.store.update(key,value,preserveTtl)}async remove(key){return this.store.remove(key)}async exists(key){return this.store.exists(key)}async readCounters(keys){return(await Promise.all(keys.map((k)=>this.read(k)))).map((r)=>{let v=r.success?r.data:null,n=typeof v==="number"?v:Number.parseFloat(String(v??""));return Number.isFinite(n)?n:0})}async incrementCounter(key,delta,ttlSeconds){if(!this.useDapr&&this.directClient){let v=await this.directClient.incrbyfloat(key,delta);if(ttlSeconds&&ttlSeconds>0)try{await this.directClient.expire(key,ttlSeconds)}catch{}return Number(v)}let cur=await this.read(key),raw=cur.success?cur.data:null,base=typeof raw==="number"?raw:Number.parseFloat(String(raw??"")),next=(Number.isFinite(base)?base:0)+delta;return await this.create(key,next,ttlSeconds),next}getDirectClient(){return this.directClient}async reauthenticate(username,password){if(this.directClient)await this.directClient.auth(username,password)}async keys(pattern){if(this.useDapr||!this.directClient)return logger.scoped("database.redis").warn("keys() not supported in Dapr mode",{pattern}),[];try{return await this.directClient.keys(pattern)}catch(error){return logger.scoped("database.redis").error("keys() failed",error,{pattern}),[]}}async acquireLock(lockKey,ttlSeconds=10){if(this.useDapr||!this.directClient){let existsResult=await this.exists(lockKey);if(!existsResult.success)return{success:!1,error:existsResult.error};if(existsResult.data)return{success:!0,data:!1};if((await this.create(lockKey,"1",ttlSeconds)).success)return{success:!0,data:!0};return{success:!1,error:"Failed to acquire lock"}}try{return{success:!0,data:await this.directClient.set(lockKey,"1","EX",ttlSeconds,"NX")==="OK"}}catch(error){return{success:!1,error:error.message}}}async releaseLock(lockKey){return this.remove(lockKey)}async waitForLock(lockKey,timeoutMs=5000,pollIntervalMs=50){let startTime=Date.now();while(Date.now()-startTime<timeoutMs){let existsResult=await this.exists(lockKey);if(!existsResult.success)return{success:!1,error:existsResult.error};if(!existsResult.data)return{success:!0,data:!0};await new Promise((resolve)=>setTimeout(resolve,pollIntervalMs))}return{success:!0,data:!1}}async getOrWait(key,timeoutMs=5000,pollIntervalMs=50){let startTime=Date.now();while(Date.now()-startTime<timeoutMs){let readResult=await this.read(key);if(!readResult.success)return{success:!1,error:readResult.error};if(readResult.data!==null)return{success:!0,data:readResult.data};await new Promise((resolve)=>setTimeout(resolve,pollIntervalMs))}return{success:!0,data:null}}}var assertRedisConfig=(config)=>{if(!config)throw Error("Redis config must be provided.");if(config.withDapr){if(!config.stateStoreName)throw Error("Dapr mode requires stateStoreName.");return}let hasUrl=Boolean(config.url),hasHostPort=Boolean(config.host)&&typeof config.port==="number";if(!hasUrl&&!hasHostPort)throw Error("Redis config requires either url or host and port.")};var init_Redis=__esm(()=>{init_Logger2();init_Dapr()});var init_Delete=__esm(()=>{init_Redis()});var init_Generate3=__esm(()=>{init_Redis();init_JWT()});var init_Read=__esm(()=>{init_Redis();init_JWT();init_Delete()});var init_Validate2=__esm(()=>{init_Read()});var init_RefreshToken=__esm(()=>{init_Delete();init_Generate3();init_Read();init_Validate2()});var DEFAULT_EXPIRY_SECONDS=86400,buildSessionKey=(sessionId)=>`session:${sessionId}`,serializeSession=(record)=>JSON.stringify(record),deserializeSession=(data)=>{if(!data)return null;if(typeof data==="object")return data;try{return JSON.parse(data)}catch{return null}};var deleteSession=async(options)=>{let manager=new RedisManager,key=buildSessionKey(options.sessionId),removeResult=await manager.remove(key);return removeResult.success&&removeResult.data>0};var init_Delete2=__esm(()=>{init_Redis()});import crypto4 from"crypto";var generateSession=async(options)=>{let manager=new RedisManager,sessionId=options.sessionId??crypto4.randomUUID(),now=Date.now(),nowIso=new Date(now).toISOString(),never=options.expiresInSeconds===null,ttlSeconds=never?void 0:options.expiresInSeconds??DEFAULT_EXPIRY_SECONDS,record={id:sessionId,userId:options.userId,createdAt:nowIso,expiresAt:never?null:new Date(now+ttlSeconds*1000).toISOString(),lastActiveAt:nowIso,clientMeta:options.clientMeta,fingerprintHash:options.fingerprintHash,deviceInfo:options.deviceInfo,refreshTokenHash:options.refreshTokenHash,loginMethod:options.loginMethod,rememberMe:options.rememberMe},writeResult=await manager.create(buildSessionKey(sessionId),serializeSession(record),ttlSeconds);if(!writeResult.success)return{success:!1,error:writeResult.error};return{success:!0,session:record}};var init_Generate4=__esm(()=>{init_Redis()});var init_Issue=__esm(()=>{init_JWT();init_Generate3();init_Delete2();init_Generate4()});var init_Session=__esm(()=>{init_Issue()});var readSession=async(options)=>{let manager=new RedisManager,key=buildSessionKey(options.sessionId),readResult=await manager.read(key);if(!readResult.success||!readResult.data)return null;let record=deserializeSession(readResult.data);if(!record)return null;if(record.expiresAt&&new Date(record.expiresAt).getTime()<=Date.now())return await deleteSession({sessionId:options.sessionId}),null;return record};var init_Read2=__esm(()=>{init_Redis();init_Delete2()});var updateSession=async(options)=>{let existing=await readSession({sessionId:options.sessionId});if(!existing)return{success:!1,error:"Session not found"};let updated={...existing,...options.updates,lastActiveAt:options.updates.lastActiveAt??new Date().toISOString()},manager=new RedisManager,remainingTtlSeconds=updated.expiresAt?Math.max(60,Math.ceil((new Date(updated.expiresAt).getTime()-Date.now())/1000)):void 0,writeResult=await manager.create(buildSessionKey(options.sessionId),serializeSession(updated),remainingTtlSeconds);if(!writeResult.success)return{success:!1,error:writeResult.error};return{success:!0,session:updated}},updateLastActiveAt=async(sessionId)=>{return updateSession({sessionId,updates:{lastActiveAt:new Date().toISOString()}})};var init_Update=__esm(()=>{init_Redis();init_Read2()});var validateSession=async(options)=>{let jwtResult=verifyJWT(options.jwtToken,options.jwtSecret);if(!jwtResult.valid)return{isValid:!1,reason:jwtResult.error};let session=await readSession({sessionId:options.sessionId});if(!session)return{isValid:!1,reason:"Session not found"};let fingerprintValid;if(options.savedFingerprint&&options.headers&&options.requestIp){let sanitizedHeaders={};for(let[key,value]of Object.entries(options.headers))if(value!==void 0)sanitizedHeaders[key]=value;let fingerprintResult=validateDeviceFingerprint({savedFingerprint:options.savedFingerprint,headers:sanitizedHeaders,requestIp:options.requestIp});if(fingerprintValid=fingerprintResult.isValid,!fingerprintResult.isValid)return{isValid:!1,reason:fingerprintResult.reason??"Fingerprint mismatch"}}return{isValid:!0,context:{userId:session.userId,sessionId:session.id,fingerprintValid}}};var init_Validate3=__esm(()=>{init_Validate();init_JWT();init_Read2()});var exports_SessionStore={};__export(exports_SessionStore,{validateSession:()=>validateSession,updateSession:()=>updateSession,updateLastActiveAt:()=>updateLastActiveAt,readSession:()=>readSession,generateSession:()=>generateSession,deleteSession:()=>deleteSession});var init_SessionStore=__esm(()=>{init_Delete2();init_Generate4();init_Read2();init_Update();init_Validate3()});var init_Auth=__esm(()=>{init_Fingerprint();init_JWT();init_Password();init_RefreshToken();init_Session();init_SessionStore()});import{eq}from"drizzle-orm";function buildClaimAction(method,entity,field,relation,relationField,isBulk){let parts=[method.toLowerCase()];if(isBulk)parts.push("bulk");if(parts.push(entity),relation){if(parts.push("with"),parts.push(relation),relationField)parts.push(relationField)}else if(field)parts.push(field);return parts.join(".")}function buildClaimPath(entity,isBulk,hasId){if(isBulk)return`/${entity}/bulk`;if(hasId)return`/${entity}/:id`;return`/${entity}`}function generateEntityClaims(entity,config,schemaRelations){let claims=[],tableName=entity.table_name,excludedMethods=entity.excluded_methods||[];for(let method of HTTP_METHODS){if(excludedMethods.includes(method))continue;let needsId=method==="PUT"||method==="PATCH"||method==="DELETE";if(claims.push({action:buildClaimAction(method,tableName),description:`${method} access to ${tableName}`,path:buildClaimPath(tableName,!1,needsId&&method!=="DELETE"),method}),method==="GET"&&entity.columns){for(let column of entity.columns){if(config.skipColumns.includes(column.name))continue;claims.push({action:buildClaimAction(method,tableName,column.name),description:`${method} access to ${tableName}.${column.name}`,path:buildClaimPath(tableName),method})}let relationKey=`${tableName.replace(/_([a-z])/g,(_,l)=>l.toUpperCase())}Relations`;if(schemaRelations[relationKey]){let relationConfig=schemaRelations[relationKey];if(relationConfig?.config?.referencedTable?._?.name){let relationName=relationConfig.config.referencedTable._.name;claims.push({action:buildClaimAction(method,tableName,void 0,relationName),description:`${method} access to ${tableName} with ${relationName}`,path:buildClaimPath(tableName),method})}}}if(method==="POST"||method==="PUT"||method==="PATCH"){if(entity.columns)for(let column of entity.columns){if(config.skipColumns.includes(column.name))continue;claims.push({action:buildClaimAction(method,tableName,column.name),description:`${method} access to ${tableName}.${column.name}`,path:buildClaimPath(tableName,!1,method!=="POST"),method})}}}if(entity.bulk_endpoints_enabled===!0)for(let method of BULK_METHODS){if(excludedMethods.includes(method))continue;claims.push({action:buildClaimAction(method,tableName,void 0,void 0,void 0,!0),description:`Bulk ${method} access to ${tableName}`,path:buildClaimPath(tableName,!0),method})}return claims}async function seedClaims(db,schemaTables,schemaRelations,entities,config,logger2){let claimsTable=schemaTables.claims;if(!claimsTable)return logger2.warn("[Authorization] Claims table not found in schema"),{total:0,created:0,existing:0,claims:[]};let allClaims=[];for(let entity of entities){if(config.skipTables.includes(entity.table_name))continue;let entityClaims=generateEntityClaims(entity,config,schemaRelations);allClaims.push(...entityClaims)}let uniqueClaims=allClaims.filter((claim,index,self2)=>index===self2.findIndex((c)=>c.action===claim.action)),created=0,existing=0,claimActions=[];for(let claim of uniqueClaims)try{if((await db.select().from(claimsTable).where(eq(claimsTable.action,claim.action)).limit(1)).length===0)await db.insert(claimsTable).values(claim),created++,claimActions.push(claim.action),logger2.debug(`[Authorization] Created claim: ${claim.action}`);else existing++}catch(error){logger2.error(`[Authorization] Failed to create claim: ${claim.action}`,error)}return logger2.info(`[Authorization] Claims seeded: ${created} created, ${existing} existing, ${uniqueClaims.length} total`),{total:uniqueClaims.length,created,existing,claims:claimActions}}var HTTP_METHODS,BULK_METHODS;var init_ClaimSeeder=__esm(()=>{HTTP_METHODS=["GET","POST","PUT","PATCH","DELETE"],BULK_METHODS=["POST","PUT","DELETE"]});function parseStoredJson(stored){if(stored===null||stored===void 0)return null;if(typeof stored==="object")return stored;if(typeof stored==="string"){if(stored.length===0)return null;try{return JSON.parse(stored)}catch{return null}}if(typeof stored==="number"||typeof stored==="boolean")return stored;return null}import{eq as eq2,isNull,or}from"drizzle-orm";function activeRowsPredicate(table){let column=table?.isActive;if(!column)return;return or(isNull(column),eq2(column,!0))}var init_activeRows=()=>{};var exports_ClaimsCache={};__export(exports_ClaimsCache,{ClaimsCache:()=>ClaimsCache});import{and,eq as eq3}from"drizzle-orm";class ClaimsCache{prefix;redis;db;schemaTables;logger;constructor(config){this.prefix=config.prefix||DEFAULT_PREFIX,this.redis=config.redis,this.db=config.db,this.schemaTables=config.schemaTables,this.logger=config.logger}key(suffix){return`${this.prefix}:${suffix}`}async buildCache(){let rolesTable=this.schemaTables.roles,roleClaimsTable=this.schemaTables.roleClaims,claimsTable=this.schemaTables.claims;if(!rolesTable||!roleClaimsTable||!claimsTable)return this.logger.warn("[ClaimsCache] Required tables not found, skipping cache build"),{version:0,roleCount:0,totalMappings:0};let allRoles=await this.db.select().from(rolesTable),roleNames=[],totalMappings=0;for(let role of allRoles){let r=role,roleId=r.id,roleName=r.name;roleNames.push(roleName);let roleClaimRows=await this.db.select().from(roleClaimsTable).innerJoin(claimsTable,eq3(roleClaimsTable.claimId,claimsTable.id)).where(and(eq3(roleClaimsTable.roleId,roleId),activeRowsPredicate(roleClaimsTable))),claimActions=[];for(let row of roleClaimRows){let action=row.claims?.action;if(action)claimActions.push(action)}await this.redis.set(this.key(`role:${roleName}`),JSON.stringify(claimActions)),totalMappings+=claimActions.length}await this.redis.set(this.key("roles"),JSON.stringify(roleNames));let newVersion=storedVersionNumber(await this.redis.get(this.key("version")))+1;return await this.redis.set(this.key("version"),String(newVersion)),this.logger.info("[ClaimsCache] Cache built",{version:newVersion,roleCount:roleNames.length,totalMappings}),{version:newVersion,roleCount:roleNames.length,totalMappings}}async getVersion(){return storedVersionNumber(await this.redis.get(this.key("version")))}async resolveClaimsForRoles(roleNames){let allClaims=new Set;for(let roleName of roleNames){let claims=parseStoredJson(await this.redis.get(this.key(`role:${roleName}`)));if(Array.isArray(claims))for(let c of claims)allClaims.add(c);else if(claims!==null)this.logger.warn("[ClaimsCache] Cached role entry unreadable, ignoring",{roleName})}return Array.from(allClaims)}async invalidate(){return(await this.buildCache()).version}getPrefix(){return this.prefix}}var DEFAULT_PREFIX="nucleus:claims",storedVersionNumber=(stored)=>{let value=parseStoredJson(stored),parsed=typeof value==="number"?value:Number.parseInt(String(value??""),10);return Number.isFinite(parsed)?parsed:0};var init_ClaimsCache=__esm(()=>{init_activeRows()});var DEFAULT_AUTHORIZATION_CONFIG,AUTHORIZATION_TABLE_KEYS,GODMIN_ROLE_NAME="godmin";var init_types3=__esm(()=>{DEFAULT_AUTHORIZATION_CONFIG={enabled:!1,autoSeedClaims:!0,skipTables:["audit_logs"],skipColumns:["id","created_at","updated_at","is_active","password","version"],excludedPaths:[],publicPaths:["/auth/login","/auth/register"]},AUTHORIZATION_TABLE_KEYS={users:"users",roles:"roles",claims:"claims",userRoles:"userRoles",roleClaims:"roleClaims"}});var{password}=globalThis.Bun;import{and as and2,eq as eq4}from"drizzle-orm";async function setupGodmin(db,schemaTables,config,logger2){if(!config.godminEmail||!config.godminPassword)return logger2.warn("[Authorization] Godmin email or password not configured, skipping godmin setup"),{success:!1};let{roles:rolesTable,users:usersTable,userRoles:userRolesTable}=schemaTables;if(!rolesTable||!usersTable||!userRolesTable)return logger2.error("[Authorization] Required tables not found for godmin setup"),{success:!1};try{let roleId,existingRole=await db.select().from(rolesTable).where(eq4(rolesTable.name,GODMIN_ROLE_NAME)).limit(1);if(existingRole.length===0){let[newRole]=await db.insert(rolesTable).values({name:GODMIN_ROLE_NAME,description:"God mode administrator - bypasses all authorization checks"}).returning();roleId=newRole.id,logger2.info(`[Authorization] Created godmin role: ${roleId}`)}else roleId=existingRole[0].id,logger2.debug(`[Authorization] Godmin role already exists: ${roleId}`);let userId,existingUser=await db.select().from(usersTable).where(eq4(usersTable.email,config.godminEmail)).limit(1);if(existingUser.length===0){let hashedPassword=await password.hash(config.godminPassword,{algorithm:"bcrypt",cost:10}),[newUser]=await db.insert(usersTable).values({email:config.godminEmail,password:hashedPassword,verifiedAt:new Date,isActive:!0,isGod:!0}).returning();userId=newUser.id,logger2.info(`[Authorization] Created godmin user: ${userId}`)}else{if(userId=existingUser[0].id,!existingUser[0].isGod)await db.update(usersTable).set({isGod:!0}).where(eq4(usersTable.id,userId)),logger2.info(`[Authorization] Marked existing godmin user as isGod=true: ${userId}`);logger2.debug(`[Authorization] Godmin user already exists: ${userId}`)}if(!((await db.select().from(userRolesTable).where(and2(eq4(userRolesTable.userId,userId),eq4(userRolesTable.roleId,roleId))).limit(1)).length>0))await db.insert(userRolesTable).values({userId,roleId}),logger2.info(`[Authorization] Assigned godmin role to user: ${userId}`);return{success:!0,userId,roleId}}catch(error){return logger2.error("[Authorization] Failed to setup godmin",error),{success:!1}}}function isGodminRole(roleName){return roleName===GODMIN_ROLE_NAME}var init_GodminSetup=__esm(()=>{init_types3()});import{and as and3,eq as eq5,inArray,sql}from"drizzle-orm";function isSelfReference(value){return value.startsWith(SELF_PREFIX)}function parseSelfReference(value){return{field:value.slice(SELF_PREFIX.length)}}function parseScopeWithSelf(scope){if(!scope)return{};let params=new URLSearchParams(scope),result={};for(let[key,value]of params.entries())if(isSelfReference(value))result[key]=parseSelfReference(value);else result[key]=value;return result}function resolveScopeWithSelf(parsedScope,userData,logger2){let resolved={},unresolved=[];for(let[key,value]of Object.entries(parsedScope))if(typeof value==="object"&&"field"in value){if(!userData){logger2.warn(`[Authorization] Cannot resolve self:${value.field} - userData not provided`),unresolved.push(key);continue}let lookup=lookupUserDataField(userData,value.field);if(!lookup.found){logger2.warn(`[Authorization] Cannot resolve self:${value.field} - field not found in userData`),unresolved.push(key);continue}resolved[key]=lookup.value,logger2.debug(`[Authorization] Resolved self:${value.field} -> ${String(lookup.value)}`)}else resolved[key]=value;return{resolved,unresolved}}function resolveClaimScopes(rows,userData,logger2){let claimScopes={},dropped=new Set,unrestricted=new Set;for(let{action,scope}of rows){if(!scope){unrestricted.add(action);continue}if(!scope.includes("="))continue;let parsed=parseScopeWithSelf(scope),{resolved,unresolved}=resolveScopeWithSelf(parsed,userData,logger2);if(unresolved.length>0){dropped.add(action);continue}claimScopes[action]={...claimScopes[action]??{},...resolved}}for(let a of unrestricted)delete claimScopes[a],dropped.delete(a);for(let a of dropped)delete claimScopes[a];return{claimScopes,dropped:Array.from(dropped)}}function mergeGrantingScopes(grantingActions,claimScopes){if(!claimScopes)return;let merged={},any=!1;for(let action of grantingActions){let s=claimScopes[action];if(!s||Object.keys(s).length===0)return;Object.assign(merged,s),any=!0}return any?merged:void 0}function buildClaimPattern(method,entity,field,relation){let parts=[method.toLowerCase(),entity];if(relation)parts.push("with",relation);else if(field)parts.push(field);return parts.join(".")}function claimMatches(userClaim,requiredPattern,requireSpecificity=!1){if(userClaim===requiredPattern)return!0;let userParts=userClaim.split("."),requiredParts=requiredPattern.split(".");if(userParts.length>requiredParts.length)return!1;if(requireSpecificity&&userParts.length<2&&requiredParts.length>=2)return!1;for(let i=0;i<userParts.length;i++)if(userParts[i]!==requiredParts[i])return!1;return!0}async function checkAuthorization(params){let{userId,method,entity,requestedFields,requestedRelations,db,schemaTables,logger:logger2,getUserData}=params,reqSpec=params.requireClaimSpecificity??!1,userData=params.userData,ensureUserData=async()=>{if(userData!==void 0)return;if(getUserData)try{userData=await getUserData()}catch(err){logger2.warn("[Authorization] getUserData callback failed",{userId,error:err instanceof Error?err.message:String(err)})}},rolesTable=schemaTables[AUTHORIZATION_TABLE_KEYS.roles],userRolesTable=schemaTables[AUTHORIZATION_TABLE_KEYS.userRoles],roleClaimsTable=schemaTables[AUTHORIZATION_TABLE_KEYS.roleClaims],claimsTable=schemaTables[AUTHORIZATION_TABLE_KEYS.claims];if(!rolesTable||!userRolesTable||!roleClaimsTable||!claimsTable)return logger2.error("[Authorization] Required tables not found"),{authorized:!1,reason:"Authorization tables not configured"};try{let userRolesCols=userRolesTable,rolesCols=rolesTable,userRoles=await db.select({roleId:userRolesCols.roleId,roleName:rolesCols.name}).from(userRolesTable).innerJoin(rolesTable,eq5(userRolesCols.roleId,rolesCols.id)).where(and3(eq5(userRolesCols.userId,userId),activeRowsPredicate(userRolesTable)));if(userRoles.length===0)return{authorized:!1,reason:"User has no roles assigned"};if(userRoles.some((ur)=>isGodminRole(ur.roleName)))return logger2.debug(`[Authorization] User ${userId} has godmin role, bypassing checks`),{authorized:!0};let roleIds=userRoles.map((ur)=>ur.roleId),roleClaimsCols=roleClaimsTable,claimsCols=claimsTable,roleClaims=await db.select({claimAction:claimsCols.action,scope:roleClaimsCols.scope}).from(roleClaimsTable).innerJoin(claimsTable,eq5(roleClaimsCols.claimId,claimsCols.id)).where(and3(inArray(roleClaimsCols.roleId,roleIds),activeRowsPredicate(roleClaimsTable)));if(roleClaims.length===0)return{authorized:!1,reason:"User roles have no claims assigned"};let entityClaimPattern=buildClaimPattern(method,entity),hasEntityAccess=roleClaims.some((rc)=>claimMatches(rc.claimAction,entityClaimPattern,reqSpec)),allowedFields=[],allowedRelations=[],scopeFilters={},unresolvedSelf=[],fieldPatterns=(requestedFields??[]).map((field)=>({field,pattern:buildClaimPattern(method,entity,field)})),relationPatterns=(requestedRelations??[]).map((relation)=>({relation,pattern:buildClaimPattern(method,entity,void 0,relation)})),claimCouldGrant=(action)=>claimMatches(action,entityClaimPattern,reqSpec)||fieldPatterns.some((f)=>claimMatches(action,f.pattern,reqSpec))||relationPatterns.some((r)=>claimMatches(action,r.pattern,reqSpec));if(roleClaims.some((rc)=>{let scope=rc.scope;return!!scope&&scope.includes("self:")&&claimCouldGrant(rc.claimAction)}))await ensureUserData();let applyClaimScope=(rc)=>{let parsedScope=parseScopeWithSelf(rc.scope),{resolved,unresolved}=resolveScopeWithSelf(parsedScope,userData,logger2);Object.assign(scopeFilters,resolved),unresolvedSelf.push(...unresolved)},denyOnUnresolvedSelf=()=>{if(unresolvedSelf.length===0)return null;return logger2.warn("[Authorization] Denying request: unresolvable self: scope (failing closed)",{userId,method,entity,unresolved:unresolvedSelf}),{authorized:!1,reason:"Ownership scope could not be resolved"}};if(hasEntityAccess){let unrestricted=!1;for(let rc of roleClaims){if(!claimMatches(rc.claimAction,entityClaimPattern,reqSpec))continue;if(!rc.scope){unrestricted=!0;continue}applyClaimScope(rc)}if(unrestricted)return{authorized:!0};let denied=denyOnUnresolvedSelf();if(denied)return denied;return{authorized:!0,scopeFilters:Object.keys(scopeFilters).length>0?scopeFilters:void 0}}let unrestrictedField=!1;for(let{field,pattern}of fieldPatterns){let granting=roleClaims.filter((rc)=>claimMatches(rc.claimAction,pattern,reqSpec));if(granting.length>0)if(allowedFields.push(field),granting.some((rc)=>!rc.scope))unrestrictedField=!0;else for(let rc of granting)applyClaimScope(rc)}for(let{relation,pattern}of relationPatterns){let granting=roleClaims.filter((rc)=>claimMatches(rc.claimAction,pattern,reqSpec));if(granting.length>0)if(allowedRelations.push(relation),granting.some((rc)=>!rc.scope))unrestrictedField=!0;else for(let rc of granting)applyClaimScope(rc)}if(!unrestrictedField){let denied=denyOnUnresolvedSelf();if(denied)return denied}if(!(allowedFields.length>0||allowedRelations.length>0))return{authorized:!1,reason:`No access to ${method} ${entity}`};return{authorized:!0,allowedFields:allowedFields.length>0?allowedFields:["id"],allowedRelations,scopeFilters:!unrestrictedField&&Object.keys(scopeFilters).length>0?scopeFilters:void 0}}catch(error){return logger2.error("[Authorization] Check failed",error),{authorized:!1,reason:"Authorization check failed"}}}function checkAuthorizationFromJWT(params){let{userClaims,userRoles,method,entity,requestedFields,requestedRelations,logger:logger2}=params,reqSpec=params.requireClaimSpecificity??!1,claimScopes=params.claimScopes;if(userClaims.length===0&&userRoles.length===0)return{authorized:!1,reason:"No roles or claims in token"};if(userRoles.some((r)=>isGodminRole(r)))return logger2.debug("[Authorization:JWT] User has godmin role, bypassing checks"),{authorized:!0};let entityClaimPattern=buildClaimPattern(method,entity),entityGranting=userClaims.filter((c)=>claimMatches(c,entityClaimPattern,reqSpec));if(entityGranting.length>0){let scopeFilters2=mergeGrantingScopes(entityGranting,claimScopes);return{authorized:!0,...scopeFilters2?{scopeFilters:scopeFilters2}:{}}}let allowedFields=[],allowedRelations=[],grantingActions=[];if(requestedFields)for(let field of requestedFields){let fieldPattern=buildClaimPattern(method,entity,field),granting=userClaims.filter((c)=>claimMatches(c,fieldPattern,reqSpec));if(granting.length>0)allowedFields.push(field),grantingActions.push(...granting)}if(requestedRelations)for(let relation of requestedRelations){let relationPattern=buildClaimPattern(method,entity,void 0,relation),granting=userClaims.filter((c)=>claimMatches(c,relationPattern,reqSpec));if(granting.length>0)allowedRelations.push(relation),grantingActions.push(...granting)}if(!(allowedFields.length>0||allowedRelations.length>0))return{authorized:!1,reason:`No access to ${method} ${entity}`};let scopeFilters=mergeGrantingScopes(grantingActions,claimScopes);return{authorized:!0,allowedFields:allowedFields.length>0?allowedFields:["id"],allowedRelations,...scopeFilters?{scopeFilters}:{}}}async function checkAuthorizationViaIDP(params){let{idpUrl,accessToken,method,entity,requestedFields,requestedRelations,logger:logger2}=params;try{let response=await fetch(`${idpUrl}/auth/check`,{method:"POST",headers:{"Content-Type":"application/json",Cookie:`access_token=${accessToken}`},body:JSON.stringify({entity,method,fields:requestedFields,relations:requestedRelations})});if(!response.ok)return logger2.warn(`[Authorization:IDP] IDP /auth/check returned ${response.status}`),{authorized:!1,reason:`IDP authorization check failed (${response.status})`};let payload=await response.json();return unwrapIdpCheckResponse(payload)}catch(error){let msg=error instanceof Error?error.message:String(error);return logger2.error(`[Authorization:IDP] Failed to reach IDP: ${msg}`),{authorized:!1,reason:"IDP authorization service unavailable"}}}function filterResponseFields(data,allowedFields){if(!allowedFields||allowedFields.length===0)return data;let fieldsToInclude=[...new Set([...["id"],...allowedFields])],toCamel=(value)=>value.replace(/_([a-z])/g,(_,letter)=>letter.toUpperCase()),allowedKeys=new Set;for(let field of fieldsToInclude)allowedKeys.add(field),allowedKeys.add(toCamel(field));let filterSingle=(item)=>{let filtered={};for(let key of Object.keys(item))if(allowedKeys.has(key))filtered[key]=item[key];return filtered};if(Array.isArray(data))return data.map(filterSingle);return filterSingle(data)}function filterResponseRelations(data,allowedRelations){if(!allowedRelations)return data;let filterSingle=(item)=>{let filtered={...item};for(let key of Object.keys(filtered))if(typeof filtered[key]==="object"&&filtered[key]!==null&&!allowedRelations.includes(key))delete filtered[key];return filtered};if(Array.isArray(data))return data.map(filterSingle);return filterSingle(data)}function buildScopeConditions(scopeFilters,resolveColumn){let conditions=[],unresolvedFields=[];if(!scopeFilters)return{conditions,unresolvedFields};for(let[field,value]of Object.entries(scopeFilters)){let col=resolveColumn(field);if(col)conditions.push(eq5(col,value));else unresolvedFields.push(field),conditions.push(sql`1 = 0`)}return{conditions,unresolvedFields}}var SELF_PREFIX="self:",toCamelCase2=(value)=>value.replace(/_([a-z])/g,(_,c)=>c.toUpperCase()),toSnakeCase=(value)=>value.replace(/([A-Z])/g,(_,c)=>`_${c.toLowerCase()}`),lookupUserDataField=(userData,fieldName)=>{if(fieldName in userData)return{found:!0,value:userData[fieldName]};let camel=toCamelCase2(fieldName);if(camel!==fieldName&&camel in userData)return{found:!0,value:userData[camel]};let snake=toSnakeCase(fieldName);if(snake!==fieldName&&snake in userData)return{found:!0,value:userData[snake]};return{found:!1}},unwrapIdpCheckResponse=(payload)=>{if(!payload||typeof payload!=="object")return{authorized:!1,reason:"IDP returned malformed response"};let envelope=payload;if(envelope.data&&typeof envelope.data==="object"){let data=envelope.data;if(typeof data.authorized==="boolean")return data}let flat=payload;if(typeof flat.authorized==="boolean")return flat;return{authorized:!1,reason:"IDP returned unrecognised response shape"}};var init_Middleware=__esm(()=>{init_activeRows();init_GodminSetup();init_types3()});var exports_SeedRunner={};__export(exports_SeedRunner,{runSeed:()=>runSeed,expandClaimPatterns:()=>expandClaimPatterns});import{and as and4,eq as eq6}from"drizzle-orm";function expandClaimPatterns(patterns,allActions){let out=new Set;for(let pattern of patterns)if(pattern.endsWith(".*")){let prefix=pattern.slice(0,-2);for(let action of allActions)if(action===prefix||action.startsWith(`${prefix}.`))out.add(action)}else out.add(pattern);return[...out]}async function runSeed(db,schemaTables,seedConfig,logger2){let{roles:rolesTable,claims:claimsTable,roleClaims:roleClaimsTable}=schemaTables,result={rolesCreated:0,rolesExisting:0,claimsCreated:0,claimsExisting:0,assignmentsCreated:0,assignmentsExisting:0,assignmentsUpdated:0};if(seedConfig.roles?.length&&rolesTable)for(let roleDef of seedConfig.roles)try{if((await db.select().from(rolesTable).where(eq6(rolesTable.name,roleDef.name)).limit(1)).length===0)await db.insert(rolesTable).values({name:roleDef.name,description:roleDef.description||""}),result.rolesCreated++,logger2.info(`[Seed] Created role: ${roleDef.name}`);else result.rolesExisting++}catch(error){logger2.error(`[Seed] Failed to seed role: ${roleDef.name}`,error)}if(seedConfig.claims?.length&&claimsTable)for(let claimDef of seedConfig.claims)try{let existing=await db.select().from(claimsTable).where(eq6(claimsTable.action,claimDef.action)).limit(1);if(existing.length===0)await db.insert(claimsTable).values({action:claimDef.action,path:claimDef.path,method:claimDef.method,description:claimDef.description||`${claimDef.method} ${claimDef.path}`,...claimDef.policy!==void 0?{policy:claimDef.policy}:{}}),result.claimsCreated++,logger2.info(`[Seed] Created claim: ${claimDef.action}`);else if(claimDef.policy!==void 0){let existingRow=existing[0],currentPolicy=JSON.stringify(existingRow.policy??null),desiredPolicy=JSON.stringify(claimDef.policy??null);if(currentPolicy!==desiredPolicy)await db.update(claimsTable).set({policy:claimDef.policy}).where(eq6(claimsTable.action,claimDef.action)),result.claimsExisting++,logger2.warn(`[Seed] Reconciled policy for claim: ${claimDef.action}`);else result.claimsExisting++}else result.claimsExisting++}catch(error){logger2.error(`[Seed] Failed to seed claim: ${claimDef.action}`,error)}if(seedConfig.roleClaimAssignments?.length&&rolesTable&&claimsTable&&roleClaimsTable){let allClaimActions=(await db.select().from(claimsTable)).map((c)=>String(c.action??""));for(let assignment of seedConfig.roleClaimAssignments){let role=(await db.select().from(rolesTable).where(eq6(rolesTable.name,assignment.role)).limit(1))[0];if(!role){logger2.warn(`[Seed] Role not found for assignment: ${assignment.role}`);continue}let roleId=role.id,resolvedActions=expandClaimPatterns(assignment.claims,allClaimActions);for(let pattern of assignment.claims)if(pattern.endsWith(".*")&&!resolvedActions.some((a)=>a.startsWith(pattern.slice(0,-1))))logger2.warn(`[Seed] No claim matched prefix pattern: ${pattern}`);for(let claimAction of resolvedActions)try{let claim=(await db.select().from(claimsTable).where(eq6(claimsTable.action,claimAction)).limit(1))[0];if(!claim){logger2.warn(`[Seed] Claim not found for assignment: ${claimAction}`);continue}let claimId=claim.id,existingAssignment=await db.select().from(roleClaimsTable).where(and4(eq6(roleClaimsTable.roleId,roleId),eq6(roleClaimsTable.claimId,claimId))).limit(1);if(existingAssignment.length===0)await db.insert(roleClaimsTable).values({roleId,claimId,scope:assignment.scope||null}),result.assignmentsCreated++;else{let existingRow=existingAssignment[0],desiredScope=assignment.scope||null,currentScope=existingRow.scope??null;if(currentScope!==desiredScope)await db.update(roleClaimsTable).set({scope:desiredScope}).where(and4(eq6(roleClaimsTable.roleId,roleId),eq6(roleClaimsTable.claimId,claimId))),result.assignmentsUpdated++,logger2.warn(`[Seed] Reconciled scope for ${assignment.role} -> ${claimAction}: ${JSON.stringify(currentScope)} => ${JSON.stringify(desiredScope)}`);else result.assignmentsExisting++}}catch(error){logger2.error(`[Seed] Failed to assign claim ${claimAction} to role ${assignment.role}`,error)}if(result.assignmentsCreated>0)logger2.info(`[Seed] Role "${assignment.role}": assigned ${result.assignmentsCreated} claims`)}}return result}var init_SeedRunner=()=>{};var init_Authorization=__esm(()=>{init_ClaimSeeder();init_ClaimsCache();init_GodminSetup();init_Middleware();init_SeedRunner();init_types3()});function parseField(raw,spec){let out=new Set;for(let part of raw.split(",")){if(part==="")return null;let[rangePart,stepPart,...extra]=part.split("/");if(extra.length>0||rangePart===void 0)return null;let step=1;if(stepPart!==void 0){if(!/^\d+$/.test(stepPart))return null;if(step=Number.parseInt(stepPart,10),step<1)return null}let from,to;if(rangePart==="*")from=spec.min,to=spec.max;else if(rangePart.includes("-")){let[a,b,...rest]=rangePart.split("-");if(rest.length>0||!isIntInRange(a,spec)||!isIntInRange(b,spec))return null;if(from=namedToNumber(a,spec),to=namedToNumber(b,spec),from>to)return null}else{if(!isIntInRange(rangePart,spec))return null;from=namedToNumber(rangePart,spec),to=stepPart===void 0?from:spec.max}for(let v=from;v<=to;v+=step)out.add(v)}return out.size>0?out:null}function isIntInRange(value,spec){if(value===void 0)return!1;let n=namedToNumber(value,spec);return n!==null&&n>=spec.min&&n<=spec.max}function namedToNumber(value,spec){if(/^\d+$/.test(value))return Number.parseInt(value,10);let lower=value.toLowerCase();if(spec===MONTH){let i=MONTH_NAMES.indexOf(lower);return i===-1?null:i+1}if(spec===WEEKDAY){let i=DAY_NAMES.indexOf(lower);return i===-1?null:i}return null}function parseCron(expression){let trimmed=expression.trim(),parts=(MACROS[trimmed.toLowerCase()]??trimmed).split(/\s+/);if(parts.length!==5)return null;let[minRaw,hourRaw,dayRaw,monthRaw,weekdayRaw]=parts,minute=parseField(minRaw,MINUTE),hour=parseField(hourRaw,HOUR),day=parseField(dayRaw,DAY),month=parseField(monthRaw,MONTH),weekdayRawSet=parseField(weekdayRaw,WEEKDAY);if(!minute||!hour||!day||!month||!weekdayRawSet)return null;let weekday=new Set([...weekdayRawSet].map((d)=>d===7?0:d));return{minute,hour,day,month,weekday,dayUnrestricted:dayRaw==="*",weekdayUnrestricted:weekdayRaw==="*"}}function formatterFor(timeZone){let cached=formatterCache.get(timeZone);if(cached)return cached;try{let fmt=new Intl.DateTimeFormat("en-US",{timeZone,hour12:!1,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",weekday:"short"});return formatterCache.set(timeZone,fmt),fmt}catch{return null}}function partsIn(ts,fmt){let parts=fmt.formatToParts(new Date(ts)),get=(type)=>parts.find((p)=>p.type===type)?.value??"0",hour=Number.parseInt(get("hour"),10)%24;return{year:Number.parseInt(get("year"),10),month:Number.parseInt(get("month"),10),day:Number.parseInt(get("day"),10),hour,minute:Number.parseInt(get("minute"),10),weekday:WEEKDAY_INDEX[get("weekday")]??0}}function offsetMsAt(ts,fmt){let p=partsIn(ts,fmt);return Date.UTC(p.year,p.month-1,p.day,p.hour,p.minute,new Date(ts).getUTCSeconds())-Math.floor(ts/1000)*1000}function zonedWallTimeToInstant(year,month,day,hour,minute,fmt){let naive=Date.UTC(year,month-1,day,hour,minute,0,0),ts=naive-offsetMsAt(naive,fmt),corrected=naive-offsetMsAt(ts,fmt);if(corrected!==ts)ts=corrected;let target=stamp(year,month,day,hour,minute),localStamp=(at)=>{let p=partsIn(at,fmt);return stamp(p.year,p.month,p.day,p.hour,p.minute)};if(localStamp(ts)===target)return ts;let probe=Math.min(ts,naive-offsetMsAt(naive,fmt));for(let i=0;i<=240;i++){if(localStamp(probe)>=target)return probe;probe+=60000}return ts}function stamp(year,month,day,hour,minute){return((year*100+month)*100+day)*1e4+hour*100+minute}function dayMatches(fields,wall){if(!fields.month.has(wall.month))return!1;let domOk=fields.day.has(wall.day),dowOk=fields.weekday.has(wall.weekday);if(fields.dayUnrestricted&&fields.weekdayUnrestricted)return!0;if(fields.dayUnrestricted)return dowOk;if(fields.weekdayUnrestricted)return domOk;return domOk||dowOk}function nextCronRun(expression,from=new Date,timeZone="UTC"){let fields=parseCron(expression);if(!fields)return null;let fmt=formatterFor(timeZone)??formatterFor("UTC");if(!fmt)return null;let hours=[...fields.hour].sort((a,b)=>a-b),minutes=[...fields.minute].sort((a,b)=>a-b),fromTs=from.getTime();if(!Number.isFinite(fromTs))return null;let cursor=partsIn(fromTs,fmt);for(let dayIndex=0;dayIndex<2929;dayIndex++){if(dayMatches(fields,cursor))for(let hour of hours)for(let minute of minutes){let ts=zonedWallTimeToInstant(cursor.year,cursor.month,cursor.day,hour,minute,fmt);if(ts>fromTs)return new Date(ts)}let nextDayUtc=Date.UTC(cursor.year,cursor.month-1,cursor.day+1,12,0,0),probe=new Date(nextDayUtc);cursor={year:probe.getUTCFullYear(),month:probe.getUTCMonth()+1,day:probe.getUTCDate(),hour:0,minute:0,weekday:probe.getUTCDay()}}return null}var MINUTE,HOUR,DAY,MONTH,WEEKDAY,MONTH_NAMES,DAY_NAMES,MACROS,formatterCache,WEEKDAY_INDEX;var init_cron=__esm(()=>{MINUTE={min:0,max:59},HOUR={min:0,max:23},DAY={min:1,max:31},MONTH={min:1,max:12},WEEKDAY={min:0,max:7};MONTH_NAMES=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"],DAY_NAMES=["sun","mon","tue","wed","thu","fri","sat"];MACROS={"@yearly":"0 0 1 1 *","@annually":"0 0 1 1 *","@monthly":"0 0 1 * *","@weekly":"0 0 * * 0","@daily":"0 0 * * *","@midnight":"0 0 * * *","@hourly":"0 * * * *"};formatterCache=new Map;WEEKDAY_INDEX={Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6}});import{createCipheriv,createDecipheriv,randomBytes as randomBytes2,scryptSync}from"crypto";var MAGIC,IV_LEN=12,TAG_LEN=16,deriveKey=(secret)=>scryptSync(secret,"nucleus-backup-v1",32),encryptBackup=(plaintext,secret)=>{if(!secret)throw Error("backup encryption key is empty");let key=deriveKey(secret),iv=randomBytes2(IV_LEN),cipher=createCipheriv("aes-256-gcm",key,iv),ciphertext=Buffer.concat([cipher.update(plaintext,"utf-8"),cipher.final()]),tag=cipher.getAuthTag();return Buffer.concat([MAGIC,iv,tag,ciphertext])},isEncryptedBackup=(buf)=>buf.length>=MAGIC.length+IV_LEN+TAG_LEN&&buf.subarray(0,MAGIC.length).equals(MAGIC),decryptBackup=(blob,secret)=>{if(!secret)throw Error("backup encryption key is empty");if(!isEncryptedBackup(blob))throw Error("not an encrypted backup");let key=deriveKey(secret),iv=blob.subarray(MAGIC.length,MAGIC.length+IV_LEN),tag=blob.subarray(MAGIC.length+IV_LEN,MAGIC.length+IV_LEN+TAG_LEN),ciphertext=blob.subarray(MAGIC.length+IV_LEN+TAG_LEN),decipher=createDecipheriv("aes-256-gcm",key,iv);return decipher.setAuthTag(tag),Buffer.concat([decipher.update(ciphertext),decipher.final()]).toString("utf-8")};var init_encryption=__esm(()=>{MAGIC=Buffer.from("NXB1")});import{mkdir as mkdir3,readFile,stat as stat2,unlink as unlink3,writeFile}from"fs/promises";import{join as join4}from"path";import{eq as eq7,getTableColumns,sql as sql2}from"drizzle-orm";function nextHopMs(delayMs){if(!Number.isFinite(delayMs)||delayMs<=0)return 0;return Math.min(delayMs,MAX_TIMEOUT_MS)}function reviveRowTypes(table,rows){let columns;try{columns=getTableColumns(table)}catch{return rows}let dateColumns=Object.entries(columns).filter(([,col2])=>col2?.dataType==="date").map(([name])=>name);if(dateColumns.length===0)return rows;return rows.map((row)=>{let copy=null;for(let name of dateColumns){let value=row[name];if(typeof value!=="string")continue;let parsed=new Date(value);if(Number.isNaN(parsed.getTime()))continue;if(!copy)copy={...row};copy[name]=parsed}return copy??row})}function normalizeTableName(name){return name.replace(/[^a-z0-9]/gi,"").toLowerCase()}function selectBackupTables(tables,excludeTables){let excluded=new Set(excludeTables.map(normalizeTableName));return Object.keys(tables).filter((name)=>{if(excluded.has(normalizeTableName(name)))return!1;let val=tables[name];if(!val||typeof val!=="object")return!1;return Object.getOwnPropertySymbols(val).length>0})}class BackupService{db;logger;config;schemaTables;schemaName;backupLogsTable;cronTimer=null;schedulerActive=!1;lock;constructor(serviceConfig){this.db=serviceConfig.db,this.logger=serviceConfig.logger,this.config=serviceConfig.config,this.schemaTables=serviceConfig.schemaTables,this.schemaName=serviceConfig.schemaName,this.backupLogsTable=serviceConfig.backupLogsTable,this.lock=serviceConfig.lock}async createBackup(trigger="manual",performedBy,targetSchemaName,targetSchemaTables){let resolvedSchema=targetSchemaName||this.schemaName,resolvedTables=targetSchemaTables||this.schemaTables,now=new Date,backupId=crypto.randomUUID(),timestamp=now.toISOString().replace(/[:.]/g,"-"),backupName=`${resolvedSchema}_${timestamp}`,fileName=`${backupName}.json`,filePath=join4(this.config.storagePath,fileName),logRecord={id:backupId,backupName,fileName,schemaName:resolvedSchema,format:this.config.format,status:"running",trigger,sizeBytes:null,tableCount:null,rowCount:null,includedTables:[],excludedTables:this.config.excludeTables,errorMessage:null,startedAt:now.toISOString(),completedAt:null,performedBy:performedBy||null,cronExpression:trigger==="scheduled"?this.config.schedule.cron:null,retentionDays:this.config.schedule.retentionDays};await this.insertLogRecord(logRecord);try{await mkdir3(this.config.storagePath,{recursive:!0});let tableNames=this.getBackupTableNames(resolvedTables),backupData=[],totalRows=0;for(let tableName of tableNames){let table=resolvedTables[tableName];if(!table)continue;try{let rows=await this.db.select().from(table),columns=Object.keys(table).filter((k)=>!k.startsWith("_")&&typeof table[k]!=="function");backupData.push({tableName,columns,rows}),totalRows+=rows.length}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.warn(`[Backup] Failed to export table ${tableName}: ${msg}`)}}let backupFile={manifest:{version:"1.0",createdAt:now.toISOString(),schemaName:resolvedSchema,format:this.config.format,tables:backupData.map((t)=>({tableName:t.tableName,rowCount:t.rows.length,columns:t.columns})),totalRows},data:backupData},jsonContent=JSON.stringify(backupFile,null,2);if(this.config.encryptionKey)await writeFile(filePath,encryptBackup(jsonContent,this.config.encryptionKey));else await writeFile(filePath,jsonContent,"utf-8");let fileStats=await stat2(filePath);return logRecord.status="completed",logRecord.completedAt=new Date().toISOString(),logRecord.tableCount=backupData.length,logRecord.rowCount=totalRows,logRecord.sizeBytes=fileStats.size,logRecord.includedTables=tableNames,await this.updateLogRecord(logRecord),this.logger.info("[Backup] Backup completed",{backupId,schemaName:resolvedSchema,tables:backupData.length,rows:totalRows,sizeBytes:fileStats.size}),await this.enforceMaxBackups(),logRecord}catch(err){let msg=err instanceof Error?err.message:String(err);return logRecord.status="failed",logRecord.errorMessage=msg,logRecord.completedAt=new Date().toISOString(),await this.updateLogRecord(logRecord),this.logger.error("[Backup] Backup failed",err,{backupId,schemaName:resolvedSchema}),logRecord}}async restoreFromBackup(backupId,performedBy,targetSchemaName,targetSchemaTables){if(!this.config.allowRestore)return{success:!1,message:"Restore is disabled in configuration"};let resolvedTables=targetSchemaTables||this.schemaTables,logRecord=await this.getLogRecord(backupId);if(!logRecord)return{success:!1,message:"Backup not found"};if(logRecord.status!=="completed")return{success:!1,message:`Cannot restore from backup with status: ${logRecord.status}`};let filePath=join4(this.config.storagePath,logRecord.fileName);try{let raw=await readFile(filePath),content;if(isEncryptedBackup(raw)){if(!this.config.encryptionKey)return{success:!1,message:"Backup is encrypted but no encryption key is configured"};content=decryptBackup(raw,this.config.encryptionKey)}else content=raw.toString("utf-8");let backupFile=JSON.parse(content);await this.createBackup("pre_restore",performedBy,targetSchemaName,targetSchemaTables);let tablesRestored=0,rowsRestored=0,ordered=backupFile.data.map((tableData)=>({tableData,table:resolvedTables[tableData.tableName]})).filter((entry)=>{if(!entry.table)return this.logger.warn(`[Backup] Skipping restore for ${entry.tableData.tableName}: table not found in schema`),!1;return!0});return await this.db.transaction(async(tx)=>{for(let{table}of[...ordered].reverse())await tx.delete(table);for(let{tableData,table}of ordered){if(tableData.rows.length===0)continue;let chunkSize=500;for(let i=0;i<tableData.rows.length;i+=chunkSize){let chunk=reviveRowTypes(table,tableData.rows.slice(i,i+chunkSize));await tx.insert(table).values(chunk)}tablesRestored++,rowsRestored+=tableData.rows.length}}),logRecord.status="restored",await this.updateLogRecord(logRecord),this.logger.info("[Backup] Restore completed",{backupId,tablesRestored,rowsRestored}),{success:!0,message:`Restored ${tablesRestored} tables with ${rowsRestored} rows`,tablesRestored,rowsRestored}}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.error("[Backup] Restore failed",err,{backupId}),{success:!1,message:`Restore failed: ${msg}`}}}async listBackups(){if(!this.backupLogsTable)return[];return await this.db.select().from(this.backupLogsTable).orderBy(sql2`created_at DESC`).limit(100)}async getBackupFilePath(backupId){let record=await this.getLogRecord(backupId);if(!record)return null;return join4(this.config.storagePath,record.fileName)}async deleteBackup(backupId){let record=await this.getLogRecord(backupId);if(!record)return!1;let filePath=join4(this.config.storagePath,record.fileName);try{await unlink3(filePath)}catch{}if(this.backupLogsTable)await this.db.delete(this.backupLogsTable).where(eq7(col(this.backupLogsTable,"id"),backupId));return!0}startScheduler(){if(!this.config.schedule.enabled||!this.config.schedule.cron)return;if(!parseCron(this.config.schedule.cron))this.logger.error("[Backup] Cron expression not understood \u2014 falling back to the default",{cron:this.config.schedule.cron,fallback:DEFAULT_CRON,expected:'five fields ("0 2 * * *", "0 3 * * MON", "*/15 * * * *") or a macro (@daily, @weekly, @monthly)'}),this.config={...this.config,schedule:{...this.config.schedule,cron:DEFAULT_CRON}};this.logger.info("[Backup] Scheduler started",{cron:this.config.schedule.cron,timeZone:this.scheduleTimeZone(),retentionDays:this.config.schedule.retentionDays,replicaSafe:Boolean(this.lock)}),this.schedulerActive=!0,this.scheduleNextRun()}scheduleTimeZone(){return this.config.schedule.timeZone||"UTC"}scheduleNextRun(){if(!this.schedulerActive)return;let now=new Date,nextRun=nextCronRun(this.config.schedule.cron,now,this.scheduleTimeZone());if(!nextRun){this.logger.error("[Backup] Cron expression matches no future time \u2014 scheduler stopped",{cron:this.config.schedule.cron}),this.schedulerActive=!1;return}let delayMs=nextRun.getTime()-now.getTime();this.logger.debug?.("[Backup] Next scheduled backup",{at:nextRun.toISOString(),inMs:delayMs});let hop=nextHopMs(delayMs);this.cronTimer=setTimeout(async()=>{if(Date.now()<nextRun.getTime()){this.scheduleNextRun();return}try{if(await this.claimScheduledRun(nextRun))this.logger.info("[Backup] Scheduled backup starting..."),await this.createBackup("scheduled"),await this.cleanupExpiredBackups()}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.error("[Backup] Scheduled backup failed",{error:msg})}finally{this.scheduleNextRun()}},hop)}async claimScheduledRun(fireTime){if(!this.lock)return!0;let key=`nucleus:backup:schedule:${this.schemaName}:${fireTime.toISOString()}`;try{let result=await this.lock.acquireLock(key,3600);if(result.success&&result.data===!1)return this.logger.info("[Backup] Another replica owns this run \u2014 skipping",{fireTime:fireTime.toISOString()}),!1;return!0}catch(err){return this.logger.warn("[Backup] Lock unavailable \u2014 running anyway",{error:err instanceof Error?err.message:String(err)}),!0}}stopScheduler(){if(this.schedulerActive=!1,this.cronTimer)clearTimeout(this.cronTimer),this.cronTimer=null,this.logger.info("[Backup] Scheduler stopped")}getBackupTableNames(tables){return selectBackupTables(tables,this.config.excludeTables)}async insertLogRecord(record){if(!this.backupLogsTable)return;try{await this.db.insert(this.backupLogsTable).values({id:record.id,backupName:record.backupName,fileName:record.fileName,schemaName:record.schemaName,format:record.format,status:record.status,trigger:record.trigger,sizeBytes:record.sizeBytes,tableCount:record.tableCount,rowCount:record.rowCount,includedTables:JSON.stringify(record.includedTables),excludedTables:JSON.stringify(record.excludedTables),errorMessage:record.errorMessage,startedAt:record.startedAt?new Date(record.startedAt):null,completedAt:record.completedAt?new Date(record.completedAt):null,performedBy:record.performedBy,cronExpression:record.cronExpression,retentionDays:record.retentionDays,createdAt:new Date,updatedAt:new Date})}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.warn(`[Backup] Failed to insert backup log: ${msg}`)}}async updateLogRecord(record){if(!this.backupLogsTable)return;try{await this.db.update(this.backupLogsTable).set({status:record.status,sizeBytes:record.sizeBytes,tableCount:record.tableCount,rowCount:record.rowCount,includedTables:JSON.stringify(record.includedTables),errorMessage:record.errorMessage,completedAt:record.completedAt?new Date(record.completedAt):null,updatedAt:new Date}).where(eq7(col(this.backupLogsTable,"id"),record.id))}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.warn(`[Backup] Failed to update backup log: ${msg}`)}}async getLogRecord(backupId){if(!this.backupLogsTable)return null;return(await this.db.select().from(this.backupLogsTable).where(eq7(col(this.backupLogsTable,"id"),backupId)).limit(1))[0]||null}async enforceMaxBackups(){if(!this.backupLogsTable)return;let allBackups=await this.db.select().from(this.backupLogsTable).where(eq7(col(this.backupLogsTable,"status"),"completed")).orderBy(sql2`created_at DESC`);if(allBackups.length>this.config.maxBackups){let toDelete=allBackups.slice(this.config.maxBackups);for(let backup of toDelete){let b=backup;await this.deleteBackup(b.id)}this.logger.info("[Backup] Old backups cleaned up",{deleted:toDelete.length})}}async cleanupExpiredBackups(){if(!this.backupLogsTable||!this.config.schedule.retentionDays)return;let cutoff=new Date;cutoff.setDate(cutoff.getDate()-this.config.schedule.retentionDays);let{lt}=await import("drizzle-orm"),expired=await this.db.select().from(this.backupLogsTable).where(lt(col(this.backupLogsTable,"createdAt"),cutoff));for(let backup of expired){let b=backup;await this.deleteBackup(b.id)}if(expired.length>0)this.logger.info("[Backup] Expired backups cleaned up",{deleted:expired.length,retentionDays:this.config.schedule.retentionDays})}}var col=(table,name)=>table[name],MAX_TIMEOUT_MS=2147483647,DEFAULT_CRON="0 2 * * *";var init_BackupService=__esm(()=>{init_cron();init_encryption()});var init_Backup=__esm(()=>{init_BackupService()});function parseTimeToSeconds(time){let match=time.match(/^(\d+)(s|m|h|d)$/);if(!match||!match[1]||!match[2])return 300;let value=Number.parseInt(match[1],10);switch(match[2]){case"s":return value;case"m":return value*60;case"h":return value*3600;case"d":return value*86400;default:return 300}}function generateSecureId(){let bytes=new Uint8Array(24);return crypto.getRandomValues(bytes),Array.from(bytes).map((b)=>b.toString(16).padStart(2,"0")).join("")}function hashAnswer(answer){let hasher=new Bun.CryptoHasher("sha256");return hasher.update(answer),hasher.digest("hex")}function timingSafeEqual(a,b){if(a.length!==b.length){let dummy=new Uint8Array(32);return crypto.getRandomValues(dummy),!1}let encoder=new TextEncoder,bufA=encoder.encode(a),bufB=encoder.encode(b),result=0;for(let i=0;i<bufA.length;i++)result|=(bufA[i]??0)^(bufB[i]??0);return result===0}function getSecureRandomInt(min,max){let range=max-min+1,bytesNeeded=Math.ceil(Math.log2(range)/8)||1,maxValue=256**bytesNeeded,limit=maxValue-maxValue%range,randomValue,bytes=new Uint8Array(bytesNeeded);do crypto.getRandomValues(bytes),randomValue=bytes.reduce((acc,byte,i)=>acc+byte*256**i,0);while(randomValue>=limit);return min+randomValue%range}function generateMathChallenge(difficulty){let config=DIFFICULTY_CONFIG[difficulty],{min,max}=config.mathRange,operations=["+","-","\xD7"],operation=operations[getSecureRandomInt(0,operations.length-1)],num1=getSecureRandomInt(min,max),num2=getSecureRandomInt(min,max),answer;switch(operation){case"+":answer=num1+num2;break;case"-":if(num1<num2)[num1,num2]=[num2,num1];answer=num1-num2;break;case"\xD7":num1=getSecureRandomInt(1,12),num2=getSecureRandomInt(1,12),answer=num1*num2;break;default:answer=num1+num2}return{question:`${num1} ${operation} ${num2} = ?`,answer:answer.toString()}}function generateTextChallenge(difficulty){let config=DIFFICULTY_CONFIG[difficulty],text="";for(let i=0;i<config.textLength;i++)text+=CHARACTERS.charAt(getSecureRandomInt(0,CHARACTERS.length-1));return{question:text,answer:text}}function generateImageChallenge(difficulty){let textChallenge=generateTextChallenge(difficulty),width=200,height=60,svgContent=generateCaptchaSVG(textChallenge.answer,200,60),imageData=`data:image/svg+xml;base64,${Buffer.from(svgContent).toString("base64")}`;return{question:"Enter the text shown in the image",answer:textChallenge.answer,imageData}}function getSecureFloat(){let bytes=new Uint32Array(1);return crypto.getRandomValues(bytes),(bytes[0]??0)/4294967295}function generateCaptchaSVG(text,width,height){let bgR=240+getSecureFloat()*15,bgG=240+getSecureFloat()*15,bgB=240+getSecureFloat()*15,bgColor=`rgb(${bgR}, ${bgG}, ${bgB})`,noiseLines="";for(let i=0;i<12;i++){let x1=getSecureFloat()*width,y1=getSecureFloat()*height,x2=getSecureFloat()*width,y2=getSecureFloat()*height,r=getSecureFloat()*100+100,g=getSecureFloat()*100+100,b=getSecureFloat()*100+100,strokeWidth=1+getSecureFloat()*2;noiseLines+=`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="rgb(${r},${g},${b})" stroke-width="${strokeWidth}"/>`}let noiseCurves="";for(let i=0;i<4;i++){let startX2=getSecureFloat()*width,startY=getSecureFloat()*height,cp1X=getSecureFloat()*width,cp1Y=getSecureFloat()*height,cp2X=getSecureFloat()*width,cp2Y=getSecureFloat()*height,endX=getSecureFloat()*width,endY=getSecureFloat()*height,r=getSecureFloat()*80+80,g=getSecureFloat()*80+80,b=getSecureFloat()*80+80;noiseCurves+=`<path d="M${startX2},${startY} C${cp1X},${cp1Y} ${cp2X},${cp2Y} ${endX},${endY}" stroke="rgb(${r},${g},${b})" stroke-width="2" fill="none"/>`}let noiseDots="";for(let i=0;i<80;i++){let x=getSecureFloat()*width,y=getSecureFloat()*height,r=getSecureFloat()*150+50,g=getSecureFloat()*150+50,b=getSecureFloat()*150+50,radius=getSecureFloat()*3+1;noiseDots+=`<circle cx="${x}" cy="${y}" r="${radius}" fill="rgb(${r},${g},${b})"/>`}let textElements="",charWidth=width/(text.length+2),startX=charWidth;for(let i=0;i<text.length;i++){let x=startX+i*charWidth+(getSecureFloat()-0.5)*15,y=height/2+8+(getSecureFloat()-0.5)*12,rotation=(getSecureFloat()-0.5)*40,fontSize=22+getSecureFloat()*10,r=getSecureFloat()*80,g=getSecureFloat()*80,b=getSecureFloat()*80,skewX=(getSecureFloat()-0.5)*15,scaleY=0.9+getSecureFloat()*0.3;textElements+=`<text x="${x}" y="${y}" font-family="Arial, Helvetica, sans-serif" font-size="${fontSize}" font-weight="bold" fill="rgb(${r},${g},${b})" transform="rotate(${rotation}, ${x}, ${y}) skewX(${skewX}) scale(1, ${scaleY})" style="font-style: ${getSecureFloat()>0.5?"italic":"normal"}">${text[i]}</text>`}let overlayLines="";for(let i=0;i<3;i++){let y=10+getSecureFloat()*(height-20),r=getSecureFloat()*60+60,g=getSecureFloat()*60+60,b=getSecureFloat()*60+60;overlayLines+=`<line x1="0" y1="${y}" x2="${width}" y2="${y+(getSecureFloat()-0.5)*20}" stroke="rgb(${r},${g},${b})" stroke-width="1.5"/>`}return`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
18
|
+
`).slice(1,4);for(let stackLine of stackLines)method(` ${dim}${stackLine.trim()}${reset}`)}let cause=entry.error.cause,indent=" ";while(cause){indent+=" ";let code=cause.code!==void 0?` [${cause.code}]`:"";method(`${indent}${color}caused by: ${cause.name}${code}: ${cause.message}${reset}`),cause=cause.cause}}}getConsoleMethod(level){switch(level){case"debug":return console.debug.bind(console);case"info":return console.info.bind(console);case"warn":return console.warn.bind(console);case"error":case"fatal":return console.error.bind(console);default:return console.log.bind(console)}}}class ServerLogTransport{name="server-log-buffer";buffer;constructor(buffer){this.buffer=buffer}log(entry){this.buffer.add(entry)}}class DatabaseAuditTransport{name="database";db;table;enabled;dedupEnabled;dedupWindowMs;dedupSlots=new Map;lastSweep=0;constructor(options){this.db=options.db,this.table=options.table,this.enabled=options.enabled??!0,this.dedupEnabled=options.dedup?.enabled??!1,this.dedupWindowMs=Math.max(1,options.dedup?.windowSeconds??60)*1000}setDb(db){this.db=db}setTable(table){this.table=table}setEnabled(enabled){this.enabled=enabled}setDedup(dedup){if(this.dedupEnabled=dedup.enabled??this.dedupEnabled,dedup.windowSeconds!=null)this.dedupWindowMs=Math.max(1,dedup.windowSeconds)*1000}isDedupable(entry){return this.dedupEnabled&&(entry.category==="auth"||entry.category==="authz"||entry.category==="security_anomaly")}sweep(now){if(now-this.lastSweep<this.dedupWindowMs)return;this.lastSweep=now;for(let[key,slot]of this.dedupSlots)if(slot.expiresAt<=now)this.dedupSlots.delete(key)}async write(entry){if(!this.enabled||!this.db||!this.table)return;try{let now=Date.now();if(this.isDedupable(entry)){this.sweep(now);let key=`${entry.ipAddress}|${entry.operation}|${entry.summary}|${entry.userId??""}`,slot=this.dedupSlots.get(key);if(slot&&slot.expiresAt>now){slot.count+=1,await this.bumpOccurrence(slot.rowId,slot.count,now);return}this.dedupSlots.set(key,{rowId:entry.id,count:1,expiresAt:now+this.dedupWindowMs})}await this.db.insert(this.table).values({id:entry.id,entityId:entry.entityId,entityName:entry.entityName,operationType:entry.operation,userId:entry.userId,ipAddress:entry.ipAddress,userAgent:entry.userAgent,summary:entry.summary,severity:entry.severity,category:entry.category,occurrenceCount:1,oldValues:entry.oldValues,newValues:entry.newValues,path:entry.path,query:entry.query})}catch(error){console.error("Audit log write failed:",error)}}async bumpOccurrence(rowId,count,nowMs){try{let{eq}=await import("drizzle-orm"),idCol=this.table.id;await this.db.update(this.table).set({occurrenceCount:count,lastOccurrenceAt:new Date(nowMs)}).where(eq(idCol,rowId))}catch(error){console.error("Audit dedup update failed:",error)}}}class ConsoleAuditTransport{name="console-audit";enabled;constructor(options={}){this.enabled=options.enabled??!0}write(entry){if(!this.enabled)return;let reset=RESET_COLOR,dim=DIM_COLOR,color={info:"\x1B[35m",low:"\x1B[90m",medium:"\x1B[33m",high:"\x1B[31m",critical:"\x1B[1m\x1B[31m"}[entry.severity]??"\x1B[35m",sev=entry.severity.toUpperCase(),actor=entry.userId||"anonymous",cat=entry.category;console.log(`${dim}${entry.timestamp}${reset} ${color}AUDIT\xB7${sev}${reset} ${dim}(${cat})${reset} [${entry.operation}] ${entry.entityName}${entry.entityId?`:${entry.entityId}`:""} ${dim}by ${actor}${reset}${entry.summary?` ${dim}\u2014${reset} ${entry.summary}`:""}`)}}var init_transports=__esm(()=>{init_ServerLogBuffer();init_types();init_utils()});class Logger{config;transports;auditTransports;context;correlationId;static instance=null;constructor(config={},context={},correlationId){this.config={...DEFAULT_CONFIG,...config},this.config.redactKeys=[...new Set([...DEFAULT_REDACT_KEYS,...config.redactKeys||[]])],this.context=context,this.correlationId=correlationId,this.transports=[new ConsoleTransport({colorize:this.config.colorize,prettyPrint:this.config.prettyPrint})],this.auditTransports=[new ConsoleAuditTransport({enabled:this.config.prettyPrint})]}static getInstance(config){if(!Logger.instance)Logger.instance=new Logger(config);return Logger.instance}static resetInstance(){Logger.instance=null}configure(config){return this.config={...this.config,...config},this.config.redactKeys=[...new Set([...DEFAULT_REDACT_KEYS,...config.redactKeys||this.config.redactKeys||[]])],this.transports=[new ConsoleTransport({colorize:this.config.colorize,prettyPrint:this.config.prettyPrint}),...this.transports.filter((t)=>t.name!=="console")],this}child(context,correlationId){let childLogger=new Logger(this.config,mergeContext(this.context,context)||{},correlationId||this.correlationId);return childLogger.transports=this.transports,childLogger.auditTransports=this.auditTransports,childLogger}withCorrelationId(correlationId){return this.child({},correlationId)}addTransport(transport){this.transports.push(transport)}addAuditTransport(transport){this.auditTransports.push(transport)}setLevel(level){this.config.level=level}setAuditEnabled(enabled){this.config.auditEnabled=enabled}isAuditEnabled(){return this.config.auditEnabled}setAuditSuppressReasons(reasons){this.config.auditSuppressReasons=reasons}setAuditMinSeverity(severity){this.config.auditMinSeverity=severity}shouldLog(level){return LOG_LEVEL_PRIORITY[level]>=LOG_LEVEL_PRIORITY[this.config.level]}shouldLogScope(scope){if(!scope)return!0;return matchesScope(scope,this.config.enabledScopes)}setEnabledScopes(scopes){this.config.enabledScopes=scopes}getEnabledScopes(){return this.config.enabledScopes}scoped(scope){return new ScopedLogger(this,scope)}createEntry(level,message,context,error,startTime,scope){let entry={timestamp:new Date().toISOString(),level,message,scope,service:this.config.service,correlationId:this.correlationId},mergedContext=mergeContext(this.context,context);if(mergedContext&&Object.keys(mergedContext).length>0)entry.context=redactSensitiveData(mergedContext,this.config.redactKeys);if(this.config.includeCallerInfo)entry.caller=getCallerInfo();if(error)entry.error=formatError(error);if(startTime!==void 0)entry.duration=performance.now()-startTime;return entry}log(level,message,context,error,startTime,scope){if(!this.shouldLog(level))return;if(!this.shouldLogScope(scope))return;let entry=this.createEntry(level,message,context,error,startTime,scope);for(let transport of this.transports)try{transport.log(entry)}catch(err){console.error(`Logger transport "${transport.name}" failed:`,err)}}debug(message,context){this.log("debug",message,context)}info(message,context){this.log("info",message,context)}warn(message,context){this.log("warn",message,context)}error(message,error,context){this.log("error",message,context,error)}fatal(message,error,context){this.log("fatal",message,context,error)}time(label){let start=performance.now();return()=>{this.log("debug",`${label} completed`,void 0,void 0,start)}}async timeAsync(label,fn,context){let start=performance.now();try{let result=await fn();return this.log("debug",`${label} completed`,context,void 0,start),result}catch(error){throw this.log("error",`${label} failed`,context,error,start),error}}request(options){let level=options.statusCode>=500?"error":options.statusCode>=400?"warn":"info";this.log(level,`${options.method} ${options.path} ${options.statusCode}`,{method:options.method,path:options.path,statusCode:options.statusCode,durationMs:options.duration,correlationId:options.correlationId,userId:options.userId,ip:options.ip,userAgent:options.userAgent})}db(options){let level=options.error?"error":"debug";this.log(level,`DB ${options.operation} on ${options.table}`,{operation:options.operation,table:options.table,durationMs:options.duration,rowCount:options.rowCount},options.error)}async flush(){for(let transport of this.transports)if(transport.flush)await transport.flush()}async audit(options){let summary=options.summary||`${options.operation} on ${options.entityName}`;if(this.config.auditSuppressReasons?.includes(summary))return;let derived=classifyAudit(options.operation,summary),severity=options.severity??derived.severity,category=options.category??derived.category;if(severityRank(severity)<severityRank(this.config.auditMinSeverity))return;let entry={id:randomId(),timestamp:new Date().toISOString(),entityName:options.entityName,entityId:options.entityId??null,operation:options.operation,userId:options.userId??null,summary,severity,category,oldValues:redactSensitiveData(options.oldValues||{},this.config.redactKeys),newValues:redactSensitiveData(options.newValues||{},this.config.redactKeys),ipAddress:options.ipAddress||"unknown",userAgent:options.userAgent||"unknown",path:options.path||"",query:options.query||"",correlationId:this.correlationId};for(let transport of this.auditTransports)try{await transport.write(entry)}catch(err){console.error(`Audit transport "${transport.name}" failed:`,err)}}auditOnly(options){this.audit(options)}async trace(options){let shouldLog=options.log!==!1,shouldAudit=options.writeAudit===!0||options.writeAudit!==!1&&this.config.auditEnabled&&options.audit;if(shouldLog)this.log(options.level||"info",options.message,options.context,options.error);if(shouldAudit&&options.audit)await this.audit(options.audit)}traceSync(options){let shouldLog=options.log!==!1,shouldAudit=options.writeAudit===!0||options.writeAudit!==!1&&this.config.auditEnabled&&options.audit;if(shouldLog)this.log(options.level||"info",options.message,options.context,options.error);if(shouldAudit&&options.audit)this.audit(options.audit)}}class ScopedLogger{parent;scope;constructor(parent,scope){this.parent=parent,this.scope=scope}debug(message,context){this.parent.log("debug",message,context,void 0,void 0,this.scope)}info(message,context){this.parent.log("info",message,context,void 0,void 0,this.scope)}warn(message,context){this.parent.log("warn",message,context,void 0,void 0,this.scope)}error(message,error,context){this.parent.log("error",message,context,error,void 0,this.scope)}}var DEFAULT_CONFIG,logger;var init_Logger=__esm(()=>{init_auditTaxonomy();init_scopes();init_transports();init_types();init_utils();DEFAULT_CONFIG={level:"info",service:"nucleus",environment:"development",redactKeys:[],colorize:!0,prettyPrint:!0,includeCallerInfo:!0,asyncBufferSize:100,flushIntervalMs:1000,auditEnabled:!1,auditSuppressReasons:DEFAULT_AUDIT_SUPPRESS_REASONS,auditMinSeverity:"info",enabledScopes:["*"]};logger=Logger.getInstance()});var require_auto_promise=__commonJS((exports,module)=>{var slice=Array.prototype.slice;module.exports=function(fn,makeResult){return function(){var promise,args=arguments,n=args.length;if(n!==0&&typeof args[n-1]!=="function")args=slice.call(arguments),promise=new Promise(function(resolve,reject){args.push(function(err,result){if(err!=null)reject(err);else resolve(makeResult!==void 0?makeResult.apply(this,slice.call(arguments,1)):result)})});return fn.apply(this,args),promise}}});var require_smb2_message=__commonJS((exports,module)=>{var protocolId=Buffer.from([254,83,77,66]),headerTranslates={Command:{NEGOTIATE:0,SESSION_SETUP:1,LOGOFF:2,TREE_CONNECT:3,TREE_DISCONNECT:4,CREATE:5,CLOSE:6,FLUSH:7,READ:8,WRITE:9,LOCK:10,IOCTL:11,CANCEL:12,ECHO:13,QUERY_DIRECTORY:14,CHANGE_NOTIFY:15,QUERY_INFO:16,SET_INFO:17,OPLOCK_BREAK:18}},headerLength=64,headerSync=function(processId,sessionId){return[["ProtocolId",4,protocolId],["StructureSize",2,headerLength],["CreditCharge",2,0],["Status",4,0],["Command",2],["Credit",2,126],["Flags",4,0],["NextCommand",4,0],["MessageId",4],["MessageIdHigh",4,0],["ProcessId",4,processId],["TreeId",4,0],["SessionId",8,sessionId],["Signature",16,0]]},headerASync=function(processId,sessionId){return[["ProtocolId",4,protocolId],["StructureSize",2,headerLength],["CreditCharge",2,0],["Status",4,0],["Command",2],["Credit",2,126],["Flags",4,0],["NextCommand",4,0],["MessageId",4],["MessageIdHigh",4,0],["AsyncId",8],["SessionId",8,sessionId],["Signature",16,0]]},SMB2Message=module.exports=function(options){if(this.headers={},options&&options.headers)this.setHeaders(options.headers);if(this.request={},options&&options.request)this.setRequest(options.request);this.response={}},proto=SMB2Message.prototype={};proto.setHeaders=function(obj){for(var key in obj)this.headers[key]=obj[key];this.structure=__require("../structures/"+this.headers.Command.toLowerCase())};proto.getHeaders=function(){return this.headers};proto.setRequest=function(request){this.request=request};proto.getResponse=function(){return this.response};proto.getBuffer=function(connection){var buffer=Buffer.allocUnsafe(65535),length=0;if(!this.isMessageIdSetted)this.isMessageIdSetted=!0,this.headers.MessageId=connection.messageId++;length+=writeHeaders(this,buffer),length+=writeRequest(this,buffer,headerLength);var output=Buffer.allocUnsafe(length);return buffer.copy(output,0,0,length),output};proto.parseBuffer=function(buffer){readHeaders(this,buffer),readResponse(this,buffer,headerLength)};function dataToBuffer(data,length){if(Buffer.isBuffer(data))return data;if(typeof data==="string")return Buffer.from(data);var result=Buffer.allocUnsafe(length);for(var i=0;i<length;i++)result.writeUInt8(255&data>>i*8,i);return result}function bufferToData(buffer){if(!Buffer.isBuffer(buffer))return buffer;var result=0;for(var i=0;i<buffer.length;i++)result+=buffer.readUInt8(i)<<i*8;return result}function writeData(buffer,data,offset,length){dataToBuffer(data,length).copy(buffer,offset,0)}function readData(buffer,offset,length){return buffer.slice(offset,offset+length)}function translate(key,value){if(headerTranslates[key]&&typeof headerTranslates[key][value]<"u")return headerTranslates[key][value];return value}function unTranslate(key,value){if(headerTranslates[key]){for(var t in headerTranslates[key])if(headerTranslates[key][t]===value)return t}return null}function readHeaders(message,buffer){var header=(message.isAsync?headerASync:headerSync)(message.ProcessId,message.SessionId),offset=0;for(var i in header){var key=header[i][0],length=header[i][1];if(message.headers[key]=readData(buffer,offset,length),length<=8)message.headers[key]=unTranslate(key,bufferToData(message.headers[key]))||message.headers[key];offset+=length}message.structure=__require("../structures/"+message.headers.Command.toLowerCase())}function writeHeaders(message,buffer){var header=(message.isAsync?headerASync:headerSync)(message.ProcessId,message.SessionId),offset=0;for(var i in header){var key=header[i][0],length=header[i][1],defaultValue=header[i][2]||0;writeData(buffer,translate(key,message.headers[key]||defaultValue),offset,length),offset+=length}return offset}function readResponse(message,buffer,offset){for(var i in message.structure.response){var key=message.structure.response[i][0],length=message.structure.response[i][1]||1;if(typeof length==="string")length=bufferToData(message.response[length]);message.response[key]=readData(buffer,offset,length),offset+=length}}function writeRequest(message,buffer,offset){var initOffset=offset,needsRewrite=!1,tmpBuffer=Buffer.allocUnsafe(buffer.length);offset=0;for(var i in message.structure.request){var key=message.structure.request[i][0],length=message.structure.request[i][1]||1,defaultValue=message.structure.request[i][2]||0;if(typeof length==="string"){if(message.request[key]=message.request[key]||"",message.request[length]!==message.request[key].length)message.request[length]=message.request[key].length,needsRewrite=!0;length=message.request[key].length}else message.request[key]=message.request[key]||defaultValue;writeData(tmpBuffer,message.request[key],offset,length),offset+=length}if(needsRewrite)writeRequest(message,tmpBuffer,0);return tmpBuffer.copy(buffer,initOffset,0,offset),offset}});var require_smb2_forge=__commonJS((exports,module)=>{var SMB2Message=require_smb2_message(),SMB2Forge=module.exports={};SMB2Forge.request=function(messageName,params,connection,cb){var msg=__require("../messages/"+messageName),smbMessage=msg.generate(connection,params);sendNetBiosMessage(connection,smbMessage);var error=Error();error.messageName=messageName,error.params=params,getResponse(connection,smbMessage.getHeaders().MessageId,msg.parse(connection,cb,error))};SMB2Forge.response=function(c){return c.responses={},c.responsesCB={},c.responseBuffer=Buffer.allocUnsafe(0),function(response){c.responseBuffer=Buffer.concat([c.responseBuffer,response]);var extract=!0;while(extract)if(extract=!1,c.responseBuffer.length>=4){var msgLength=(c.responseBuffer.readUInt8(1)<<16)+c.responseBuffer.readUInt16BE(2);if(c.responseBuffer.length>=msgLength+4){extract=!0;var r=c.responseBuffer.slice(4,msgLength+4),message=new SMB2Message;if(message.parseBuffer(r),c.debug)console.log("--response"),console.log(r.toString("hex"));var mId=message.getHeaders().MessageId.toString("hex");if(c.responsesCB[mId])c.responsesCB[mId](message),delete c.responsesCB[mId];else c.responses[mId]=message;c.responseBuffer=c.responseBuffer.slice(msgLength+4)}}}};function sendNetBiosMessage(connection,message){var smbRequest=message.getBuffer(connection);if(connection.debug)console.log("--request"),console.log(smbRequest.toString("hex"));var buffer=Buffer.allocUnsafe(smbRequest.length+4);return buffer.writeUInt8(0,0),buffer.writeUInt8((16711680&smbRequest.length)>>16,1),buffer.writeUInt16BE(65535&smbRequest.length,2),smbRequest.copy(buffer,4,0,smbRequest.length),connection.newResponse=!1,connection.socket.write(buffer),!0}function getResponse(c,mId,cb){var messageId=Buffer.allocUnsafe(4);if(messageId.writeUInt32LE(mId,0),messageId=messageId.toString("hex"),c.responses[messageId])cb(c.responses[messageId]),delete c.responses[messageId];else c.responsesCB[messageId]=cb}});var require_smb2_connection=__commonJS((exports,module)=>{var net=__require("net"),SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,SMB2Connection=module.exports={};SMB2Connection.close=function(connection){if(clearAutoCloseTimeout(connection),connection.connected)connection.connected=!1,connection.socket.end()};SMB2Connection.requireConnect=function(method){return function(){var connection=this,args=Array.prototype.slice.call(arguments);connect(connection,function(err){var cb=args.pop();if(typeof cb!=="function")args.push(cb),cb=function(err2){if(err2){if(!(err2 instanceof Error))err2=Error(String(err2));throw err2}};if(cb=scheduleAutoClose(connection,cb),args.push(cb),err)cb(err);else method.apply(connection,args)})}};SMB2Connection.init=function(connection){connection.connected=!1,connection.socket=new net.Socket({allowHalfOpen:!0}),connection.socket.on("data",SMB2Forge.response(connection)),connection.errorHandler=[],connection.socket.on("error",function(err){if(connection.errorHandler.length>0)connection.errorHandler[0].call(null,err);if(connection.debug)console.log("-- error"),console.log(arguments)})};function connect(connection,cb){if(connection.connected){cb&&cb(null);return}cb=scheduleAutoClose(connection,cb),connection.messageId=0,connection.SessionId=Math.floor(Math.random()*256)&255,connection.socket.connect(connection.port,connection.ip),SMB2Request("negotiate",{},connection,function(err){if(err)cb&&cb(err);else SMB2Request("session_setup_step1",{},connection,function(err2){if(err2)cb&&cb(err2);else SMB2Request("session_setup_step2",{},connection,function(err3){if(err3)cb&&cb(err3);else SMB2Request("tree_connect",{},connection,function(err4){if(err4)cb&&cb(err4);else connection.connected=!0,cb&&cb(null)})})})})}function clearAutoCloseTimeout(connection){if(connection.scheduledAutoClose)clearTimeout(connection.scheduledAutoClose),connection.scheduledAutoClose=null}function setAutoCloseTimeout(connection){if(clearAutoCloseTimeout(connection),connection.autoCloseTimeout!==0)connection.scheduledAutoClose=setTimeout(function(){SMB2Connection.close(connection)},connection.autoCloseTimeout)}function scheduleAutoClose(connection,cb){return addErrorListener(connection,cb),clearAutoCloseTimeout(connection),function(){removeErrorListener(connection),setAutoCloseTimeout(connection),cb.apply(null,arguments)}}function addErrorListener(connection,callback){connection.errorHandler.unshift(callback)}function removeErrorListener(connection){connection.errorHandler.shift()}});var require_disconnect=__commonJS((exports,module)=>{var SMB2Connection=require_smb2_connection();module.exports=function(){SMB2Connection.close(this)}});var require_exists=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request;module.exports=function(path,cb){var connection=this;SMB2Request("open",{path},connection,function(err,file){if(err!=null){if(err.code==="STATUS_OBJECT_NAME_NOT_FOUND"||err.code==="STATUS_OBJECT_PATH_NOT_FOUND")return cb&&cb(null,!1);return cb&&cb(err)}SMB2Request("close",file,connection,function(){cb&&cb(null,!0)})})}});var require_bigint=__commonJS((exports,module)=>{var BigInt2=module.exports=function(n,v){if(BigInt2.isBigInt(n))this.buffer=Buffer.allocUnsafe(n.buffer.length),n.buffer.copy(this.buffer,0),this.sign=n.sign;else if(this.buffer=Buffer.alloc(n),this.sign=1,v=v||0,v!==0){if(v<0)this.sign=-1,v=-v;v=v.toString(16);var size=Math.ceil(v.length/2),carry=size*2-v.length;for(var i=0;i<size;i++){var start=(size-i-1)*2-carry;this.buffer.writeUInt8(parseInt(start===-1?v.substr(0,1):v.substr(start,2),16),i)}}};BigInt2.isBigInt=function(v){return v&&v.buffer&&Buffer.isBuffer(v.buffer)};BigInt2.toBigInt=function(n,v){return new BigInt2(n,v)};BigInt2.fromBuffer=function(b,sign){sign=typeof sign>"u"?1:sign;var bi=new BigInt2(0);return bi.sign=sign,bi.buffer=b,bi};BigInt2.prototype.add=function(v){if(!BigInt2.isBigInt(v))v=BigInt2.toBigInt(this.buffer.length,v);if(this.sign!==v.sign)return this.neg().sub(v);var carry=0,n=Math.max(v.buffer.length,this.buffer.length),result=new BigInt2(n);for(var i=0;i<n;i++){var r=(i<this.buffer.length?this.buffer.readUInt8(i):0)+(i<v.buffer.length?v.buffer.readUInt8(i):0)+carry;result.buffer.writeUInt8(r&255,i),carry=r>>8}return result.sign=this.sign,result};BigInt2.prototype.neg=function(){var result=new BigInt2(this);return result.sign*=-1,result};BigInt2.prototype.abs=function(){var result=new BigInt2(this);return result.sign=1,result};BigInt2.prototype.sub=function(v){if(!BigInt2.isBigInt(v))v=BigInt2.toBigInt(this.buffer.length,v);if(this.sign!==v.sign)return this.add(v.neg());var carry=0,a=new BigInt2(this),b=new BigInt2(v),n=Math.max(a.buffer.length,b.buffer.length),result=new BigInt2(n),sign=this.sign;if(a.abs().lt(b.abs())){var t=a;a=b,b=t,sign*=-1}for(var i=0;i<n;i++){var va=i<a.buffer.length?a.buffer.readUInt8(i):0,vb=i<b.buffer.length?b.buffer.readUInt8(i):0,c=0,r=va-vb-carry;while(r<0)r+=255,c--;result.buffer.writeUInt8(r&255,i),carry=(r>>8)+c}return result.sign=sign,result};BigInt2.prototype.toBuffer=function(){return this.buffer};BigInt2.prototype.toNumber=function(){var b=Buffer.allocUnsafe(this.buffer.length);for(var i=0;i<this.buffer.length;i++)b.writeUInt8(this.buffer.readUInt8(this.buffer.length-i-1),i);return parseInt(b.toString("hex"),16)};BigInt2.prototype.compare=function(v){if(!BigInt2.isBigInt(v))v=BigInt2.toBigInt(this.buffer.length,v);var n=Math.max(v.buffer.length,this.buffer.length);if(this.sign>v.sign)return 1;if(this.sign<v.sign)return-1;for(var i=n-1;i>=0;i--){var a=i<this.buffer.length?this.buffer.readUInt8(i):0,b=i<v.buffer.length?v.buffer.readUInt8(i):0;if(a!==b)return a>b?this.sign:-this.sign}return 0};BigInt2.prototype.lt=function(v){return this.compare(v)<0};BigInt2.prototype.le=function(v){return this.compare(v)<=0};BigInt2.prototype.gt=function(v){return this.compare(v)>0};BigInt2.prototype.ge=function(v){return this.compare(v)>=0}});var require_constants=__commonJS((exports,module)=>{module.exports={FILE_SUPERSEDE:0,FILE_OPEN:1,FILE_CREATE:2,FILE_OPEN_IF:3,FILE_OVERWRITE:4,FILE_OVERWRITE_IF:5,MAX_READ_LENGTH:65536,MAX_WRITE_LENGTH:65423,FILE_SHARE_NONE:0,FILE_SHARE_READ:1,FILE_SHARE_WRITE:2,FILE_SHARE_DELETE:4,DELETE:65536,FILE_APPEND_DATA:4,FILE_DELETE_CHILD:64,FILE_READ_ATTRIBUTES:128,FILE_READ_DATA:1,FILE_READ_EA:8,FILE_WRITE_ATTRIBUTES:256,FILE_WRITE_DATA:2,FILE_WRITE_EA:16,READ_CONTROL:131072,SYNCHRONIZE:1048576,WRITE_DAC:262144,DIRECTORY:16}});var require_rename=__commonJS((exports,module)=>{var BigInt2=require_bigint(),SMB2Request=require_smb2_forge().request,constants=require_constants();module.exports=function(oldPath,newPath,options,cb){if(typeof options==="function")cb=options,options={};var connection=this;SMB2Request("open_folder",{path:oldPath},connection,function(err,file){if(err)SMB2Request("create",{path:oldPath,createDisposition:constants.FILE_OPEN,shareAccess:constants.FILE_SHARE_DELETE},connection,function(err2,file2){if(err2)cb&&cb(err2);else rename_(connection,file2,newPath,options,cb)});else rename_(connection,file,newPath,options,cb)})};function rename_(connection,file,newPath,options,cb){SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileRenameInformation",Buffer:renameBuffer(newPath,options)},connection,function(err){SMB2Request("close",file,connection,function(){if(err)cb&&cb(err);else cb&&cb(null)})})}function renameBuffer(newPath,options){var filename=Buffer.from(newPath,"ucs2");return Buffer.concat([new BigInt2(1,options.replace?1:0).toBuffer(),new BigInt2(7,0).toBuffer(),new BigInt2(8,0).toBuffer(),new BigInt2(4,filename.length).toBuffer(),filename])}});var require_readFile=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint(),MAX_READ_LENGTH=require_constants().MAX_READ_LENGTH;module.exports=function(filename,options,cb){var connection=this;if(typeof options==="function")cb=options,options={};SMB2Request("open",{path:filename},connection,function(err,file){if(err)cb&&cb(err);else{var fileLength=0,offset=new BigInt2(8),stop=!1,nbRemainingPackets=0;for(var i=0;i<file.EndofFile.length;i++)fileLength+=file.EndofFile[i]*Math.pow(2,i*8);var result=Buffer.allocUnsafe(fileLength),callback=function(offset2){return function(err2,content){if(stop)return;if(err2)cb&&cb(err2),stop=!0;else content.copy(result,offset2.toNumber()),nbRemainingPackets--,checkDone()}},checkDone=function(){if(stop)return;if(createPackets(),nbRemainingPackets===0&&offset.ge(fileLength))SMB2Request("close",file,connection,function(){if(options.encoding)result=result.toString(options.encoding);cb&&cb(null,result)})},createPackets=function(){while(nbRemainingPackets<connection.packetConcurrency&&offset.lt(fileLength)){var rest=offset.sub(fileLength).neg(),packetSize=rest.gt(MAX_READ_LENGTH)?MAX_READ_LENGTH:rest.toNumber();SMB2Request("read",{FileId:file.FileId,Length:packetSize,Offset:offset.toBuffer()},connection,callback(offset)),offset=offset.add(packetSize),nbRemainingPackets++}};checkDone()}})}});var require_createReadStream=__commonJS((exports,module)=>{var Readable=__require("stream").Readable,BigInt2=require_bigint(),request=require_smb2_forge().request,MAX_READ_LENGTH=require_constants().MAX_READ_LENGTH;module.exports=function(path,options,cb){if(typeof options==="function")cb=options,options={};else if(options==null)options={};var connection=this,fd=options.fd,isFd=fd!=null,shouldClose=!isFd||options.autoClose==null||options.autoClose;function onOpen(err,file){if(err!=null)return cb(err);var offset=options.start||0,fileSize=BigInt2.fromBuffer(file.EndofFile).toNumber(),end=fileSize;if(options.end<end)end=options.end+1;var close=request.bind(void 0,"close",file,connection),stream=new Readable;if(stream.fileSize=fileSize,shouldClose)stream._destroy=function(err2,cb2){close(function(err22){if(err22!=null)return cb2(err22);cb2(err2)})};var running=!1;stream._read=function(size){if(running)return;if(offset>=end)return shouldClose?close(function(){stream.push(null)}):stream.push(null);running=!0,request("read",{FileId:file.FileId,Length:Math.min(MAX_READ_LENGTH,size,end-offset),Offset:new BigInt2(8,offset).toBuffer()},connection,function(err2,content){if(running=!1,err2!=null)return process.nextTick(stream.emit.bind(stream,"error",err2));offset+=content.length,stream.push(content)})},cb(null,stream)}if(isFd)onOpen(null,fd);else request("open",{path},connection,onOpen)}});var require_parse_flags=__commonJS((exports,module)=>{var c=require_constants();module.exports=function(flags){var chars={__proto__:null};for(var i=0,n=flags.length;i<n;++i)chars[flags[i]]=!0;if("r"in chars)return c.FILE_OPEN;if("x"in chars)return c.FILE_CREATE;if("a"in chars)return c.FILE_OPEN_IF;if("w"in chars)return c.FILE_OVERWRITE_IF;throw Error("invalid flags")}});var require_createWriteStream=__commonJS((exports,module)=>{var Writable=__require("stream").Writable,BigInt2=require_bigint(),constants=require_constants(),parseFlags=require_parse_flags(),request=require_smb2_forge().request;module.exports=function(path,options,cb){if(typeof options==="function")cb=options,options={};var connection=this,fd=options.fd,isFd=fd!=null,shouldClose=!isFd||options.autoClose==null||options.autoClose;function onCreate(err,file){if(err!=null)return cb(err);var offset=new BigInt2(8,options!=null&&options.start||0);function write(buffer,i,cb2){var j=i+constants.MAX_WRITE_LENGTH,chunk=buffer.slice(i,j);request("write",{Buffer:chunk,FileId:file.FileId,Offset:offset.toBuffer()},connection,function(err2){if(err2!=null)return cb2(err2);if(offset=offset.add(chunk.length),j<buffer.length)return write(buffer,j,cb2);cb2()})}var stream=new Writable;if(shouldClose){var close=request.bind(void 0,"close",file,connection);stream._destroy=function(err2,cb2){close(function(err22){if(err22!=null)return cb2(err22);cb2(err2)})},stream._final=close}stream._write=function(chunk,encoding,next){write(Buffer.isBuffer(chunk)?chunk:Buffer.from(chunk,encoding),0,next)},cb(null,stream)}if(isFd)onCreate(null,fd);else request("create",{createDisposition:parseFlags(options!=null&&options.flags||"wx"),path},connection,onCreate)}});var require_writeFile=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint(),constants=require_constants(),parseFlags=require_parse_flags();module.exports=function(filename,data,options,cb){if(typeof options==="function")cb=options,options={};options.encoding=options.encoding||"utf8";var connection=this,file,fileContent=Buffer.isBuffer(data)?data:Buffer.from(data,options.encoding),fileLength=new BigInt2(8,fileContent.length);function createFile(fileCreated){SMB2Request("create",{createDisposition:parseFlags(options!=null&&(options.flags||options.flag)||"wx"),path:filename},connection,function(err,f){if(err)cb&&cb(err);else file=f,fileCreated()})}function closeFile(fileClosed){SMB2Request("close",file,connection,function(err){if(err)cb&&cb(err);else file=null,fileClosed()})}function setFileSize(fileSizeSetted){SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileEndOfFileInformation",Buffer:fileLength.toBuffer()},connection,function(err){if(err)cb&&cb(err);else fileSizeSetted()})}function writeFile(fileWritten){var offset=new BigInt2(8),stop=!1,nbRemainingPackets=0,maxPacketSize=new BigInt2(8,constants.MAX_WRITE_LENGTH);function callback(){return function(err){if(stop)return;if(err)cb&&cb(err),stop=!0;else nbRemainingPackets--,checkDone()}}function checkDone(){if(stop)return;if(createPackets(),nbRemainingPackets===0&&offset.ge(fileLength))fileWritten()}function createPackets(){while(nbRemainingPackets<connection.packetConcurrency&&offset.lt(fileLength)){var rest=fileLength.sub(offset),packetSize=rest.gt(maxPacketSize)?maxPacketSize:rest;SMB2Request("write",{FileId:file.FileId,Offset:offset.toBuffer(),Buffer:fileContent.slice(offset.toNumber(),offset.add(packetSize).toNumber())},connection,callback(offset)),offset=offset.add(packetSize),nbRemainingPackets++}}checkDone()}createFile(function(){setFileSize(function(){writeFile(function(){closeFile(cb)})})})}});var require_unlink=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint(),constants=require_constants();module.exports=function(path,cb){var connection=this;SMB2Request("create",{path,shareAccess:constants.FILE_SHARE_DELETE},connection,function(err,file){if(err)cb&&cb(err);else SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileDispositionInformation",Buffer:new BigInt2(1,1).toBuffer()},connection,function(err2,files){SMB2Request("close",file,connection,function(){if(err2)cb&&cb(err2);else cb&&cb(null,files)})})})}});var require_convert_time=__commonJS((exports,module)=>{var winTicks=1e7,uEpoch=11644473600;module.exports=function(time){var unixTime=time/winTicks-uEpoch;return new Date(unixTime*1000)}});var require_stats=__commonJS((exports,module)=>{var convert=require_convert_time(),BigInt2=require_bigint(),DIRECTORY=require_constants().DIRECTORY;module.exports=function(file){return{birthtime:convert(BigInt2.fromBuffer(file.CreationTime).toNumber()),atime:convert(BigInt2.fromBuffer(file.LastAccessTime).toNumber()),mtime:convert(BigInt2.fromBuffer(file.LastWriteTime).toNumber()),ctime:convert(BigInt2.fromBuffer(file.ChangeTime).toNumber()),size:BigInt2.fromBuffer(file.EndofFile).toNumber(),isDirectory:function(){var attr=file.FileAttributes;if(typeof attr!=="number")attr=BigInt2.fromBuffer(attr).toNumber();return(attr&DIRECTORY)==DIRECTORY}}}});var require_readdir=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,stats=require_stats();module.exports=function(path,options,cb){var connection=this;if(typeof options==="function")cb=options,options={};var mapping=options.stats?function(v){var obj=stats(v);return obj.name=v.Filename,obj}:function(v){return v.Filename};function queryDirectory(filesBatch,file,connection2,cb2){SMB2Request("query_directory",file,connection2,function(err,files){if(err)if(err.code==="STATUS_NO_MORE_FILES")cb2(null,filesBatch);else cb2(err);else filesBatch.push(files.filter(function(v){return v.Filename!=="."&&v.Filename!==".."}).map(mapping)),queryDirectory(filesBatch,file,connection2,cb2)})}function openDirectory(path2,connection2,cb2){SMB2Request("open",{path:path2},connection2,function(err,file){if(err)cb2(err);else return cb2(null,file)})}function closeDirectory(file,connection2,cb2){SMB2Request("close",file,connection2,function(err,res){if(err){if(err.code!=="STATUS_FILE_CLOSED")cb2(err)}cb2(null,res)})}openDirectory(path,connection,function(err,file){var totalFiles=[],filesBatch=[];if(err)cb(err);else queryDirectory(filesBatch,file,connection,function(err2,file2){if(err2)cb(err2);else closeDirectory(file2,connection,function(err3,file3){if(err3)cb(err3);else totalFiles=[].concat(...filesBatch),cb(null,totalFiles)})})})}});var require_rmdir=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint();module.exports=function(path,cb){var connection=this;SMB2Request("open_folder",{path},connection,function(err,file){if(err)cb&&cb(err);else SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileDispositionInformation",Buffer:new BigInt2(1,1).toBuffer()},connection,function(err2,files){SMB2Request("close",file,connection,function(){if(err2)return cb(err2);cb(null,files)})})})}});var require_mkdir=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request;module.exports=function(path,mode,cb){if(typeof mode==="function")cb=mode,mode="0777";var connection=this;SMB2Request("create_folder",{path},connection,function(err,file){if(err)cb&&cb(err);else SMB2Request("close",file,connection,function(){cb&&cb(null)})})}});var require_getSize=__commonJS((exports,module)=>{var BigInt2=require_bigint(),request=require_smb2_forge().request;module.exports=function(path,cb){var connection=this;request("open",{path},connection,function(err,file){if(err!=null)return cb(err);request("close",file,connection,function(){cb(null,BigInt2.fromBuffer(file.EndofFile).toNumber())})})}});var require_stat=__commonJS((exports,module)=>{var stats=require_stats(),request=require_smb2_forge().request;module.exports=function(path,cb){var connection=this;request("open",{path},connection,function(err,file){if(err!=null)return cb(err);request("close",file,connection,function(){cb(null,stats(file))})})}});var require_open=__commonJS((exports,module)=>{var parseFlags=require_parse_flags(),request=require_smb2_forge().request;module.exports=function(path,flags,cb){if(typeof flags==="function")cb=flags,flags=void 0;request("create",{createDisposition:parseFlags(flags||"r"),path},this,cb)}});var require_read=__commonJS((exports,module)=>{var assert=__require("assert"),BigInt2=require_bigint(),request=require_smb2_forge().request,MAX_READ_LENGTH=require_constants().MAX_READ_LENGTH;module.exports=function(file,buffer,offset,length,start,cb){assert(start!==null,"null pos is not supported");var connection=this,end=Math.min(start+length,BigInt2.fromBuffer(file.EndofFile).toNumber()),pos=start;function onRead(err,chunk){if(err!=null)return cb(err,pos-start,buffer);chunk.copy(buffer,offset);var n=chunk.length;offset+=n,pos+=n,readChunk()}function readChunk(){if(pos>=end)return cb(null,pos-start,buffer);request("read",{FileId:file.FileId,Length:Math.min(MAX_READ_LENGTH,end-pos),Offset:new BigInt2(8,pos).toBuffer()},connection,onRead)}process.nextTick(readChunk)}});var require_write=__commonJS((exports,module)=>{var assert=__require("assert"),BigInt2=require_bigint(),request=require_smb2_forge().request,MAX_WRITE_LENGTH=require_constants().MAX_WRITE_LENGTH;module.exports=function(file,buffer,offset,length,start,cb){if(assert(Buffer.isBuffer(buffer)),offset==null)offset=0;else assert.strictEqual(typeof offset,"number"),assert(offset>0),assert(offset<buffer.length);if(length==null)length=buffer.length-offset;else assert.strictEqual(typeof length,"number"),assert(length>0),length=Math.min(length,buffer.length-offset);assert.strictEqual(typeof start,"number");var connection=this,pos=start,chunkLength;function onWrite(err){if(err!=null)return cb(err,pos-start,buffer);length-=chunkLength,offset+=chunkLength,pos+=chunkLength,writeChunk()}function writeChunk(){if(length<=0)return cb(null,pos-start,buffer);chunkLength=Math.min(MAX_WRITE_LENGTH,length),request("write",{Buffer:buffer.slice(offset,offset+chunkLength),FileId:file.FileId,Offset:new BigInt2(8,pos).toBuffer()},connection,onWrite)}process.nextTick(writeChunk)}});var require_close=__commonJS((exports,module)=>{var request=require_smb2_forge().request;module.exports=function(file,cb){request("close",file,this,cb)}});var require_truncate=__commonJS((exports,module)=>{var SMB2Forge=require_smb2_forge(),SMB2Request=SMB2Forge.request,BigInt2=require_bigint(),FILE_WRITE_DATA=require_constants().FILE_WRITE_DATA;function setFileSize(file,fileLength,connection,cb){SMB2Request("set_info",{FileId:file.FileId,FileInfoClass:"FileEndOfFileInformation",Buffer:fileLength.toBuffer()},connection,cb)}module.exports=function(path,length,cb){var connection=this;SMB2Request("open",{path,desiredAccess:FILE_WRITE_DATA},connection,function(err,file){if(err!=null)return cb(err);setFileSize(file,new BigInt2(8,length),connection,function(err2){SMB2Request("close",file,connection,function(){cb(err2)})})})}});var require_smb2=__commonJS((exports,module)=>{var shareRegExp=/\\\\([^\\]*)\\([^\\]*)\\?/,port=445,packetConcurrency=20,autoCloseTimeout=1e4,autoPromise=require_auto_promise(),SMB2Connection=require_smb2_connection(),SMB=module.exports=function(opt){opt=opt||{};var matches;if(!opt.share||!(matches=opt.share.match(shareRegExp)))throw Error("the share is not valid");if(this.ip=matches[1],this.port=opt.port||port,this.share=matches[2],this.fullPath=opt.share,this.packetConcurrency=opt.packetConcurrency||packetConcurrency,opt.autoCloseTimeout!==void 0)this.autoCloseTimeout=opt.autoCloseTimeout;else this.autoCloseTimeout=autoCloseTimeout;this.domain=opt.domain,this.username=opt.username,this.password=opt.password,this.ProcessId=Buffer.from([Math.floor(Math.random()*256)&255,Math.floor(Math.random()*256)&255,Math.floor(Math.random()*256)&255,Math.floor(Math.random()*256)&254]),this.debug=opt.debug,SMB2Connection.init(this)},proto=SMB.prototype={};proto.disconnect=require_disconnect();proto.exists=autoPromise(SMB2Connection.requireConnect(require_exists()));proto.rename=autoPromise(SMB2Connection.requireConnect(require_rename()));proto.readFile=autoPromise(SMB2Connection.requireConnect(require_readFile()));proto.createReadStream=autoPromise(SMB2Connection.requireConnect(require_createReadStream()));proto.createWriteStream=autoPromise(SMB2Connection.requireConnect(require_createWriteStream()));proto.writeFile=autoPromise(SMB2Connection.requireConnect(require_writeFile()));proto.unlink=autoPromise(SMB2Connection.requireConnect(require_unlink()));proto.readdir=autoPromise(SMB2Connection.requireConnect(require_readdir()));proto.rmdir=autoPromise(SMB2Connection.requireConnect(require_rmdir()));proto.mkdir=autoPromise(SMB2Connection.requireConnect(require_mkdir()));proto.getSize=autoPromise(SMB2Connection.requireConnect(require_getSize()));proto.stat=autoPromise(SMB2Connection.requireConnect(require_stat()));proto.open=autoPromise(SMB2Connection.requireConnect(require_open()));proto.read=autoPromise(require_read(),function(bytesRead,buffer){return{bytesRead,buffer}});proto.write=autoPromise(require_write(),function(bytesWritten,buffer){return{bytesWritten,buffer}});proto.close=autoPromise(require_close());proto.truncate=autoPromise(SMB2Connection.requireConnect(require_truncate()))});import{createHash,randomBytes}from"crypto";var API_KEY_BYTE_LENGTH=32,HASH_ALGORITHM="sha256",generateApiKey=(prefix="nk_live")=>{let randomPart=randomBytes(API_KEY_BYTE_LENGTH).toString("hex"),rawKey=`${prefix}_${randomPart}`,keyHash=hashApiKey(rawKey),keyPreview=`${prefix}_...${randomPart.slice(-4)}`;return{rawKey,keyHash,keyPreview}},hashApiKey=(rawKey)=>{return createHash(HASH_ALGORITHM).update(rawKey).digest("hex")},validateApiKeyFormat=(rawKey)=>{return/^nk_(live|test)_[a-f0-9]{64}$/.test(rawKey)},extractApiKeyFromHeader=(headers)=>{let apiKeyHeader=headers.get("x-api-key");if(apiKeyHeader&&validateApiKeyFormat(apiKeyHeader))return apiKeyHeader;let authHeader=headers.get("authorization");if(authHeader){let bearerMatch=authHeader.match(/^Bearer\s+(nk_(?:live|test)_[a-f0-9]{64})$/);if(bearerMatch?.[1])return bearerMatch[1]}return null},validateApiKeyRecord=(record)=>{if(!record.isActive)return{valid:!1,reason:"API key is inactive"};if(record.revokedAt)return{valid:!1,reason:"API key has been revoked"};if(record.expiresAt&&new Date(record.expiresAt)<new Date)return{valid:!1,reason:"API key has expired"};return{valid:!0,record}},intersectPermissions=(userPermissions,keyPermissions)=>{let userSet=new Set(userPermissions);return keyPermissions.filter((p)=>userSet.has(p))};var init_ApiKey=()=>{};var normalize=(value)=>{return value?.trim().toLowerCase()||"unknown"},extractHeaderValue=(headers,key)=>{return headers[key.toLowerCase()]??headers[key]};import crypto2 from"crypto";var generateDeviceFingerprint=(input)=>{let payload=JSON.stringify({userAgent:normalize(input.userAgent),extra:input.extra??{}});return{hash:crypto2.createHash("sha256").update(payload).digest("base64url"),components:input}};var init_Generate=()=>{};var validateDeviceFingerprint=({savedFingerprint,requestIp,headers})=>{let userAgent=extractHeaderValue(headers,"user-agent"),forwardedFor=extractHeaderValue(headers,"x-forwarded-for")??requestIp??void 0,currentFingerprint=generateDeviceFingerprint({userAgent,ipAddress:forwardedFor}),componentMismatch=[{field:"userAgent",saved:savedFingerprint.components.userAgent,received:userAgent},{field:"ipAddress",saved:savedFingerprint.components.ipAddress,received:forwardedFor}].find(({saved,received})=>saved??(received??"")!=="");if(componentMismatch)return{isValid:!1,reason:`${componentMismatch.field} mismatch`,currentFingerprint};return{isValid:!0,currentFingerprint}};var init_Validate=__esm(()=>{init_Generate()});var init_Fingerprint=__esm(()=>{init_Generate();init_Validate()});import crypto3 from"crypto";var base64UrlEncode=(data)=>{return(Buffer.isBuffer(data)?data.toString("base64"):Buffer.from(data).toString("base64")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},base64UrlDecode=(data)=>{let padding="=".repeat((4-data.length%4)%4),base64=data.replace(/-/g,"+").replace(/_/g,"/")+padding;return Buffer.from(base64,"base64").toString("utf-8")},createSignature=(data,secret,algorithm)=>{let hmacAlgorithm=algorithm.replace("HS","sha"),hmac=crypto3.createHmac(hmacAlgorithm,secret);return hmac.update(data),base64UrlEncode(hmac.digest())},verifySignature=(data,signature,secret,algorithm)=>{let expectedSignature=createSignature(data,secret,algorithm),sigBuf=Buffer.from(signature),expBuf=Buffer.from(expectedSignature);if(sigBuf.length!==expBuf.length)return!1;return crypto3.timingSafeEqual(sigBuf,expBuf)},encodeHeader=(header)=>{return base64UrlEncode(JSON.stringify(header))},encodePayload=(payload)=>{return base64UrlEncode(JSON.stringify(payload))},decodeHeader=(encoded)=>{try{return JSON.parse(base64UrlDecode(encoded))}catch{return null}},decodePayload=(encoded)=>{try{return JSON.parse(base64UrlDecode(encoded))}catch{return null}};var init_utils2=()=>{};var decodeJWT=(token)=>{let parts=token.split(".");if(parts.length!==3)return null;let[encodedHeader,encodedPayload,signature]=parts;if(!encodedHeader||!encodedPayload||!signature)return null;let header=decodeHeader(encodedHeader),payload=decodePayload(encodedPayload);if(!header||!payload)return null;return{header,payload,signature}};var init_Decode=__esm(()=>{init_utils2()});import{randomUUID}from"crypto";var signJWT=(options,secret,algorithm="HS256")=>{let header={alg:algorithm,typ:"JWT"},now=Math.floor(Date.now()/1000),payload={sub:options.subject,iat:now,...options.expiresInSeconds===null?{}:{exp:now+options.expiresInSeconds},iss:options.issuer,aud:options.audience,jti:options.jwtId||randomUUID(),sessionId:options.sessionId,...options.customClaims},encodedHeader=encodeHeader(header),encodedPayload=encodePayload(payload),dataToSign=`${encodedHeader}.${encodedPayload}`,signature=createSignature(dataToSign,secret,algorithm);return`${dataToSign}.${signature}`};var init_Sign=__esm(()=>{init_utils2()});var audienceMatches=(aud,expected)=>{if(typeof aud==="string")return aud===expected;if(Array.isArray(aud))return aud.includes(expected);return!1},verifyJWT=(token,secret,expected)=>{let parts=token.split(".");if(parts.length!==3)return{valid:!1,error:"Invalid token format: expected 3 parts"};let[encodedHeader,encodedPayload,signature]=parts;if(!encodedHeader||!encodedPayload||!signature)return{valid:!1,error:"Invalid token format: missing parts"};let header=decodeHeader(encodedHeader);if(!header)return{valid:!1,error:"Invalid header: failed to decode"};if(header.typ!=="JWT")return{valid:!1,error:"Invalid header: typ must be JWT"};if(!["HS256","HS384","HS512"].includes(header.alg))return{valid:!1,error:`Unsupported algorithm: ${header.alg}`};let dataToVerify=`${encodedHeader}.${encodedPayload}`;if(!verifySignature(dataToVerify,signature,secret,header.alg))return{valid:!1,error:"Invalid signature"};let payload=decodePayload(encodedPayload);if(!payload)return{valid:!1,error:"Invalid payload: failed to decode"};let now=Math.floor(Date.now()/1000);if(payload.exp&&payload.exp<now)return{valid:!1,error:"Token expired"};if(payload.iat&&payload.iat>now+60)return{valid:!1,error:"Token issued in the future"};if(expected?.issuer&&payload.iss!==expected.issuer)return{valid:!1,error:"Invalid issuer"};if(expected?.audience&&!audienceMatches(payload.aud,expected.audience))return{valid:!1,error:"Invalid audience"};return{valid:!0,payload}};var init_Verify=__esm(()=>{init_utils2()});var exports_JWT={};__export(exports_JWT,{verifyJWT:()=>verifyJWT,signJWT:()=>signJWT,decodeJWT:()=>decodeJWT});var init_JWT=__esm(()=>{init_Decode();init_Sign();init_Verify()});var init_Generate2=()=>{};var init_Password=__esm(()=>{init_Generate2()});var init_Logger2=__esm(()=>{init_auditTaxonomy();init_Logger();init_ServerLogBuffer();init_transports();init_utils();init_scopes()});var DEFAULT_DAPR_HOST="127.0.0.1",DEFAULT_DAPR_PORT="3500",DEFAULT_MAX_BODY_SIZE_MB=4,DEFAULT_STATE_STORE="statestore-redis",DEFAULT_PUBSUB_NAME="pubsub-rabbitmq",DEFAULT_SECRET_STORE="secretstore",DEFAULT_CONFIG_STORE="configstore-redis",ENV_DAPR_HOST="DAPR_HOST",ENV_DAPR_HTTP_PORT="DAPR_HTTP_PORT",ENV_DAPR_HTTP_ENDPOINT="DAPR_HTTP_ENDPOINT",ENV_DAPR_GRPC_ENDPOINT="DAPR_GRPC_ENDPOINT",ENV_DAPR_API_TOKEN="DAPR_API_TOKEN",DEFAULT_OPERATION_TIMEOUT_MS=30000,DEFAULT_CONNECTION_TIMEOUT_MS=1e4,DEFAULT_HEALTH_CHECK_TIMEOUT_MS=5000,CONNECTION_STATUS,HEALTH_STATUS,ERROR_CODES;var init_constants=__esm(()=>{CONNECTION_STATUS={CONNECTED:"connected",DISCONNECTED:"disconnected",CONNECTING:"connecting",ERROR:"error"},HEALTH_STATUS={HEALTHY:"healthy",UNHEALTHY:"unhealthy"},ERROR_CODES={CONNECTION_ERROR:"DAPR_CONNECTION_ERROR",TIMEOUT_ERROR:"DAPR_TIMEOUT_ERROR",STATE_ERROR:"DAPR_STATE_ERROR",PUBSUB_ERROR:"DAPR_PUBSUB_ERROR",BINDING_ERROR:"DAPR_BINDING_ERROR",SECRET_ERROR:"DAPR_SECRET_ERROR",CONFIG_ERROR:"DAPR_CONFIG_ERROR",INVOKE_ERROR:"DAPR_INVOKE_ERROR",CRYPTO_ERROR:"DAPR_CRYPTO_ERROR",LOCK_ERROR:"DAPR_LOCK_ERROR",WORKFLOW_ERROR:"DAPR_WORKFLOW_ERROR",VALIDATION_ERROR:"DAPR_VALIDATION_ERROR"}});var DaprManagerError,createConnectionError=(message,details)=>new DaprManagerError(ERROR_CODES.CONNECTION_ERROR,message,details),createTimeoutError=(message,details)=>new DaprManagerError(ERROR_CODES.TIMEOUT_ERROR,message,details),createStateError=(message,details)=>new DaprManagerError(ERROR_CODES.STATE_ERROR,message,details),createPubSubError=(message,details)=>new DaprManagerError(ERROR_CODES.PUBSUB_ERROR,message,details),createBindingError=(message,details)=>new DaprManagerError(ERROR_CODES.BINDING_ERROR,message,details),createSecretError=(message,details)=>new DaprManagerError(ERROR_CODES.SECRET_ERROR,message,details),createConfigError=(message,details)=>new DaprManagerError(ERROR_CODES.CONFIG_ERROR,message,details),createInvokeError=(message,details)=>new DaprManagerError(ERROR_CODES.INVOKE_ERROR,message,details),createCryptoError=(message,details)=>new DaprManagerError(ERROR_CODES.CRYPTO_ERROR,message,details),createLockError=(message,details)=>new DaprManagerError(ERROR_CODES.LOCK_ERROR,message,details),createWorkflowError=(message,details)=>new DaprManagerError(ERROR_CODES.WORKFLOW_ERROR,message,details),safeExecute=async(operation,errorCreator)=>{try{return await operation()}catch(error){let errorMessage=error instanceof Error?error.message:String(error);throw errorCreator(errorMessage,error)}};var init_error_handling=__esm(()=>{init_constants();DaprManagerError=class DaprManagerError extends Error{code;details;constructor(code,message,details){super(message);this.name="DaprManagerError",this.code=code,this.details=details}toJSON(){return{code:this.code,message:this.message,details:this.details}}}});var LOG_LEVEL_PRIORITY2,createDefaultLogger=(minLevel="info")=>{let minPriority=LOG_LEVEL_PRIORITY2[minLevel],scoped=logger.scoped("dapr.client"),logWithLevel=(level)=>(message,...meta)=>{if(LOG_LEVEL_PRIORITY2[level]<minPriority)return;let context=meta.length>0?{meta}:void 0;if(level==="error")scoped.error(message,void 0,context);else scoped[level](message,context)};return{debug:logWithLevel("debug"),info:logWithLevel("info"),warn:logWithLevel("warn"),error:logWithLevel("error")}},withTimeout=async(fn,timeoutMs,errorMessage="Operation timed out")=>{return Promise.race([fn(),new Promise((_,reject)=>{setTimeout(()=>{reject(createTimeoutError(errorMessage))},timeoutMs)})])},validateRequired=(params,requiredKeys,entityName)=>{let missingKeys=requiredKeys.filter((key)=>params[key]===void 0);if(missingKeys.length>0)throw Error(`Missing required ${entityName} parameters: ${missingKeys.join(", ")}`)};var init_utils3=__esm(()=>{init_Logger2();init_constants();init_error_handling();LOG_LEVEL_PRIORITY2={debug:0,info:1,warn:2,error:3}});class DaprBindingClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async invoke(name,operation,data,options={}){return validateRequired({name,operation},["name","operation"],"binding invoke"),safeExecute(async()=>{this.logger.debug("Invoking binding",{name,operation});let response=await(await this.client()).binding.send(name,operation,data,options.metadata);return this.logger.debug("Binding invoked successfully",{name,operation}),response},(message,details)=>createBindingError(`Failed to invoke binding ${name}: ${message}`,details))}}var init_binding_client=__esm(()=>{init_error_handling();init_utils3()});class DaprConfigClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async get(keys,storeName=DEFAULT_CONFIG_STORE){if(validateRequired({keys,storeName},["keys","storeName"],"config get"),keys.length===0)return{};return safeExecute(async()=>{this.logger.debug("Getting configuration",{keys,storeName});let response=await(await this.client()).configuration.get(storeName,keys);return this.logger.debug("Configuration retrieved",{keys,storeName,itemCount:Object.keys(response.items||{}).length}),response.items||{}},(message,details)=>createConfigError(`Failed to get configuration: ${message}`,details))}async subscribeWithKeys(keys,callback,storeName=DEFAULT_CONFIG_STORE){if(validateRequired({keys,callback,storeName},["keys","callback","storeName"],"config subscribeWithKeys"),keys.length===0)throw createConfigError("At least one key must be provided for subscription");return safeExecute(async()=>{this.logger.debug("Subscribing to configuration updates",{keys,storeName});let stream=await(await this.client()).configuration.subscribeWithKeys(storeName,keys,async(data)=>{try{this.logger.debug("Received configuration update",{storeName,updatedKeys:Object.keys(data.items||{})}),await callback(data)}catch(error){this.logger.error("Error in configuration subscription callback",error)}});return this.logger.debug("Configuration subscription established",{keys,storeName}),{stop:()=>{this.logger.debug("Stopping configuration subscription",{keys,storeName}),stream.stop()}}},(message,details)=>createConfigError(`Failed to subscribe to configuration updates: ${message}`,details))}async getValue(key,storeName=DEFAULT_CONFIG_STORE){return(await this.get([key],storeName))[key]?.value}async getValues(keys,storeName=DEFAULT_CONFIG_STORE){let items=await this.get(keys,storeName),values={};for(let key in items)if(items[key]?.value!==void 0)values[key]=items[key].value;return values}}var init_config_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprCryptoClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async encrypt(data,options){return validateRequired({data,componentName:options.componentName},["data","componentName"],"crypto encrypt"),safeExecute(async()=>{this.logger.debug("Encrypting data",{componentName:options.componentName,keyName:options.keyName,keyWrapAlgorithm:options.keyWrapAlgorithm});let client=await this.client(),inputData=typeof data==="string"?Buffer.from(data):data,cryptoOptions={componentName:options.componentName};if(options.keyName)cryptoOptions.keyName=options.keyName;if(options.keyWrapAlgorithm)cryptoOptions.keyWrapAlgorithm=options.keyWrapAlgorithm;let encryptedData=await client.crypto.encrypt(inputData,cryptoOptions);return this.logger.debug("Data encrypted successfully",{componentName:options.componentName,inputSize:inputData.length,outputSize:encryptedData.length}),encryptedData},(message,details)=>createCryptoError(`Failed to encrypt data: ${message}`,details))}async decrypt(data,options){return validateRequired({data,componentName:options.componentName},["data","componentName"],"crypto decrypt"),safeExecute(async()=>{this.logger.debug("Decrypting data",{componentName:options.componentName});let client=await this.client(),inputData=typeof data==="string"?Buffer.from(data):data,cryptoOptions={componentName:options.componentName};if(options.keyName)cryptoOptions.keyName=options.keyName;if(options.keyWrapAlgorithm)cryptoOptions.keyWrapAlgorithm=options.keyWrapAlgorithm;let decryptedData=await client.crypto.decrypt(inputData,cryptoOptions);return this.logger.debug("Data decrypted successfully",{componentName:options.componentName,inputSize:inputData.length,outputSize:decryptedData.length}),decryptedData},(message,details)=>createCryptoError(`Failed to decrypt data: ${message}`,details))}async encryptString(plaintext,options){return(await this.encrypt(plaintext,options)).toString("base64")}async decryptString(ciphertext,options){let encryptedBuffer=Buffer.from(ciphertext,"base64");return(await this.decrypt(encryptedBuffer,options)).toString("utf-8")}}var init_crypto_client=__esm(()=>{init_error_handling();init_utils3()});function dapr(){if(!cachedDapr)cachedDapr=__require("@dapr/dapr");return cachedDapr}class DaprInvokeClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async invoke(appId,methodName,httpMethod,data,options={}){httpMethod??=dapr().HttpMethod.POST,validateRequired({appId,methodName,httpMethod},["appId","methodName","httpMethod"],"invoke service");let timeoutMs=options.timeout||DEFAULT_OPERATION_TIMEOUT_MS;return safeExecute(async()=>{this.logger.debug("Invoking service",{appId,methodName,httpMethod,hasData:data!==void 0});let fullMethodName=methodName;if(options.queryParams&&Object.keys(options.queryParams).length>0){let queryString=Object.entries(options.queryParams).map(([key,value])=>`${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");fullMethodName=`${methodName}?${queryString}`}let client=await this.client(),response=await withTimeout(()=>client.invoker.invoke(appId,fullMethodName,httpMethod,data,options.headers),timeoutMs,`Service invocation timed out after ${timeoutMs}ms`);if(this.logger.debug("Service invoked successfully",{appId,methodName,httpMethod,status:response?.status}),!response)return;if("data"in response)return response.data;return response},(message,details)=>createInvokeError(`Failed to invoke service ${appId}.${methodName}: ${message}`,details))}async get(appId,methodName,options={}){return this.invoke(appId,methodName,dapr().HttpMethod.GET,void 0,options)}async post(appId,methodName,data,options={}){return this.invoke(appId,methodName,dapr().HttpMethod.POST,data,options)}async put(appId,methodName,data,options={}){return this.invoke(appId,methodName,dapr().HttpMethod.PUT,data,options)}async delete(appId,methodName,options={}){return this.invoke(appId,methodName,dapr().HttpMethod.DELETE,void 0,options)}}var cachedDapr=null;var init_invoke_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprLockClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async lock(storeName,resourceId,lockOwner,options){return validateRequired({storeName,resourceId,lockOwner,expiryInSeconds:options.expiryInSeconds},["storeName","resourceId","lockOwner","expiryInSeconds"],"lock"),safeExecute(async()=>{this.logger.debug("Acquiring lock",{storeName,resourceId,lockOwner});let response=await(await this.client()).lock.lock(storeName,resourceId,lockOwner,options.expiryInSeconds);return this.logger.debug("Lock acquisition result",{storeName,resourceId,lockOwner,success:response.success}),{success:response.success}},(message,details)=>createLockError(`Failed to acquire lock for resource ${resourceId}: ${message}`,details))}async unlock(storeName,resourceId,lockOwner){return validateRequired({storeName,resourceId,lockOwner},["storeName","resourceId","lockOwner"],"unlock"),safeExecute(async()=>{this.logger.debug("Releasing lock",{storeName,resourceId,lockOwner});let response=await(await this.client()).lock.unlock(storeName,resourceId,lockOwner);return this.logger.debug("Lock release result",{storeName,resourceId,lockOwner,status:this.getLockStatusName(response.status)}),{status:response.status}},(message,details)=>createLockError(`Failed to release lock for resource ${resourceId}: ${message}`,details))}getLockStatusName(status){switch(status){case 0:return"Success";case 1:return"LockDoesNotExist";case 2:return"LockBelongsToOthers";default:return"InternalError"}}}var init_lock_client=__esm(()=>{init_error_handling();init_utils3()});class DaprPubSubClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async publish(topic,data,options={},pubsubName=DEFAULT_PUBSUB_NAME){return validateRequired({topic,data,pubsubName},["topic","data","pubsubName"],"pubsub publish"),safeExecute(async()=>{this.logger.debug("Publishing message to topic",{topic,pubsubName}),await(await this.client()).pubsub.publish(pubsubName,topic,data,{metadata:options.metadata,contentType:options.contentType}),this.logger.debug("Message published successfully",{topic,pubsubName})},(message,details)=>createPubSubError(`Failed to publish message to topic ${topic}: ${message}`,details))}async publishBulk(topic,messages,pubsubName=DEFAULT_PUBSUB_NAME){if(validateRequired({topic,messages,pubsubName},["topic","messages","pubsubName"],"pubsub publishBulk"),messages.length===0)return{failedEntries:[]};return safeExecute(async()=>{this.logger.debug("Publishing bulk messages to topic",{topic,pubsubName,messageCount:messages.length});let client=await this.client(),daprMessages=messages.map((msg)=>{if(typeof msg==="object"&&"event"in msg)return{entryID:msg.entryId,event:msg.event,contentType:msg.contentType,metadata:msg.metadata};return{event:msg}}),response=await client.pubsub.publishBulk(pubsubName,topic,daprMessages),failedCount=response.failedMessages?.length||0;if(failedCount>0)this.logger.warn("Some messages failed to publish",{topic,pubsubName,failedCount,totalCount:messages.length});else this.logger.debug("All bulk messages published successfully",{topic,pubsubName,messageCount:messages.length});return{failedEntries:(response.failedMessages||[]).map((failed)=>({entryId:failed.message.entryID||"",error:failed.error?.message||"Unknown error"}))}},(message,details)=>createPubSubError(`Failed to publish bulk messages to topic ${topic}: ${message}`,details))}createBulkPublishMessage(event,entryId,contentType,metadata){return{entryId,event,contentType,metadata}}}var init_pubsub_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprSecretClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async get(key,options={},storeName=DEFAULT_SECRET_STORE){return validateRequired({key,storeName},["key","storeName"],"secret get"),safeExecute(async()=>{this.logger.debug("Getting secret",{key,storeName});let client=await this.client(),metadataStr=options.metadata?JSON.stringify(options.metadata):void 0,result=await client.secret.get(storeName,key,metadataStr);return this.logger.debug("Secret retrieved",{key,storeName}),result},(message,details)=>createSecretError(`Failed to get secret ${key}: ${message}`,details))}async getBulk(_options={},storeName=DEFAULT_SECRET_STORE){return validateRequired({storeName},["storeName"],"secret getBulk"),safeExecute(async()=>{this.logger.debug("Getting all secrets",{storeName});let result=await(await this.client()).secret.getBulk(storeName);return this.logger.debug("All secrets retrieved",{storeName,secretCount:Object.keys(result).length}),result},(message,details)=>createSecretError(`Failed to get all secrets: ${message}`,details))}}var init_secret_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprStateClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async save(stateItems,options={},storeName=DEFAULT_STATE_STORE){if(validateRequired({stateItems,storeName},["stateItems","storeName"],"state save"),stateItems.length===0)return;return safeExecute(async()=>{this.logger.debug("Saving state items",{count:stateItems.length,storeName}),await(await this.client()).state.save(storeName,stateItems,options),this.logger.debug("State items saved successfully",{count:stateItems.length,storeName})},(message,details)=>createStateError(`Failed to save state items: ${message}`,details))}async get(key,storeName=DEFAULT_STATE_STORE){return validateRequired({key,storeName},["key","storeName"],"state get"),safeExecute(async()=>{this.logger.debug("Getting state item",{key,storeName});let result=await(await this.client()).state.get(storeName,key);if(this.logger.debug("State item retrieved",{key,storeName,found:result!==void 0}),result===void 0||result===null)return;if(typeof result==="string")try{return JSON.parse(result)}catch{return result}if(typeof result==="object")return result;return result},(message,details)=>createStateError(`Failed to get state item ${key}: ${message}`,details))}async getBulk(keys,storeName=DEFAULT_STATE_STORE){if(validateRequired({keys,storeName},["keys","storeName"],"state getBulk"),keys.length===0)return{};return safeExecute(async()=>{this.logger.debug("Getting bulk state items",{count:keys.length,storeName});let results=await(await this.client()).state.getBulk(storeName,keys),resultMap={};return results.forEach((item)=>{if(item.data!==void 0)resultMap[item.key]=item.data}),this.logger.debug("Bulk state items retrieved",{count:keys.length,found:Object.keys(resultMap).length,storeName}),resultMap},(message,details)=>createStateError(`Failed to get bulk state items: ${message}`,details))}async delete(key,etag,metadata,storeName=DEFAULT_STATE_STORE){return validateRequired({key,storeName},["key","storeName"],"state delete"),safeExecute(async()=>{this.logger.debug("Deleting state item",{key,storeName});let client=await this.client(),options={};if(etag)options.etag=etag;if(metadata)options.metadata=metadata;await client.state.delete(storeName,key,options),this.logger.debug("State item deleted",{key,storeName})},(message,details)=>createStateError(`Failed to delete state item ${key}: ${message}`,details))}async transaction(operations,storeName=DEFAULT_STATE_STORE){if(validateRequired({operations,storeName},["operations","storeName"],"state transaction"),operations.length===0)return;return safeExecute(async()=>{this.logger.debug("Executing state transaction",{operationCount:operations.length,storeName});let client=await this.client(),daprOperations=operations.map((op)=>({operation:op.operation,request:{key:op.request.key,value:op.request.value,etag:op.request.etag?{value:op.request.etag}:void 0,metadata:op.request.metadata}}));await client.state.transaction(storeName,daprOperations),this.logger.debug("State transaction executed successfully",{operationCount:operations.length,storeName})},(message,details)=>createStateError(`Failed to execute state transaction: ${message}`,details))}async query(query,storeName=DEFAULT_STATE_STORE){return validateRequired({query,storeName},["query","storeName"],"state query"),safeExecute(async()=>{this.logger.debug("Querying state store",{storeName});let result=await(await this.client()).state.query(storeName,query);return this.logger.debug("State query executed",{storeName,resultCount:result.results?.length||0}),(result.results||[]).map((item)=>item.data)},(message,details)=>createStateError(`Failed to query state store: ${message}`,details))}async saveItem(key,value,options={},storeName=DEFAULT_STATE_STORE){let stateItem={key,value};return this.save([stateItem],options,storeName)}async upsert(key,value,options={},storeName=DEFAULT_STATE_STORE){return this.saveItem(key,value,options,storeName)}}var init_state_client=__esm(()=>{init_constants();init_error_handling();init_utils3()});class DaprWorkflowClient{client;logger;constructor(clientProvider,logger2){this.client=clientProvider,this.logger=logger2}async start(workflowName,input,options={}){return validateRequired({workflowName},["workflowName"],"workflow start"),safeExecute(async()=>{this.logger.debug("Starting workflow",{workflowName,instanceId:options.instanceId||"auto-generated",workflowComponent:options.workflowComponent});let instanceId=await(await this.client()).workflow.start(workflowName,input,options.instanceId);return this.logger.debug("Workflow started",{workflowName,instanceId}),instanceId},(message,details)=>createWorkflowError(`Failed to start workflow ${workflowName}: ${message}`,details))}async get(instanceId){return validateRequired({instanceId},["instanceId"],"workflow get"),safeExecute(async()=>{this.logger.debug("Getting workflow instance",{instanceId});let instance=await(await this.client()).workflow.get(instanceId);return this.logger.debug("Workflow instance retrieved",{instanceId,workflowName:instance.workflowName,runtimeStatus:instance.runtimeStatus}),{instanceId:instance.instanceID,workflowName:instance.workflowName,createdAt:new Date(instance.createdAt),lastUpdatedAt:new Date(instance.lastUpdatedAt),runtimeStatus:instance.runtimeStatus,properties:instance.properties||{}}},(message,details)=>createWorkflowError(`Failed to get workflow instance ${instanceId}: ${message}`,details))}async terminate(instanceId){return validateRequired({instanceId},["instanceId"],"workflow terminate"),safeExecute(async()=>{this.logger.debug("Terminating workflow instance",{instanceId}),await(await this.client()).workflow.terminate(instanceId),this.logger.debug("Workflow instance terminated",{instanceId})},(message,details)=>createWorkflowError(`Failed to terminate workflow instance ${instanceId}: ${message}`,details))}async pause(instanceId){return validateRequired({instanceId},["instanceId"],"workflow pause"),safeExecute(async()=>{this.logger.debug("Pausing workflow instance",{instanceId}),await(await this.client()).workflow.pause(instanceId),this.logger.debug("Workflow instance paused",{instanceId})},(message,details)=>createWorkflowError(`Failed to pause workflow instance ${instanceId}: ${message}`,details))}async resume(instanceId){return validateRequired({instanceId},["instanceId"],"workflow resume"),safeExecute(async()=>{this.logger.debug("Resuming workflow instance",{instanceId}),await(await this.client()).workflow.resume(instanceId),this.logger.debug("Workflow instance resumed",{instanceId})},(message,details)=>createWorkflowError(`Failed to resume workflow instance ${instanceId}: ${message}`,details))}async purge(instanceId){return validateRequired({instanceId},["instanceId"],"workflow purge"),safeExecute(async()=>{this.logger.debug("Purging workflow instance",{instanceId}),await(await this.client()).workflow.purge(instanceId),this.logger.debug("Workflow instance purged",{instanceId})},(message,details)=>createWorkflowError(`Failed to purge workflow instance ${instanceId}: ${message}`,details))}async raiseEvent(instanceId,eventName,eventData){return validateRequired({instanceId,eventName},["instanceId","eventName"],"workflow raiseEvent"),safeExecute(async()=>{this.logger.debug("Raising event for workflow instance",{instanceId,eventName}),await(await this.client()).workflow.raise(instanceId,eventName,eventData),this.logger.debug("Event raised for workflow instance",{instanceId,eventName})},(message,details)=>createWorkflowError(`Failed to raise event ${eventName} for workflow instance ${instanceId}: ${message}`,details))}}var init_workflow_client=__esm(()=>{init_error_handling();init_utils3()});function dapr2(){if(!cachedDapr2)cachedDapr2=__require("@dapr/dapr");return cachedDapr2}class DaprConnectionManager{client=null;daprHost;daprPort;communicationProtocolOption;maxBodySizeMb;daprApiToken;logger;connectionStatus=CONNECTION_STATUS.DISCONNECTED;connectionPromise=null;constructor(options={}){this.daprHost=options.daprHost||process.env[ENV_DAPR_HOST]||DEFAULT_DAPR_HOST,this.daprPort=options.daprPort||process.env[ENV_DAPR_HTTP_PORT]||DEFAULT_DAPR_PORT,this.communicationProtocolOption=options.communicationProtocol,this.maxBodySizeMb=options.maxBodySizeMb||DEFAULT_MAX_BODY_SIZE_MB,this.daprApiToken=options.daprApiToken||process.env[ENV_DAPR_API_TOKEN],this.logger=options.logger||createDefaultLogger(),this.logger.info("DaprConnectionManager initialized",{daprHost:this.daprHost,daprPort:this.daprPort,communicationProtocol:this.communicationProtocolOption??"default (HTTP)"})}get communicationProtocol(){return this.communicationProtocolOption??dapr2().CommunicationProtocolEnum.HTTP}async getClient(){if(!this.client||this.connectionStatus!==CONNECTION_STATUS.CONNECTED)await this.connect();if(!this.client)throw createConnectionError("Not connected to Dapr sidecar");return this.client}async connect(){if(this.connectionPromise)return this.connectionPromise;if(this.client&&this.connectionStatus===CONNECTION_STATUS.CONNECTED)return Promise.resolve();this.connectionStatus=CONNECTION_STATUS.CONNECTING,this.connectionPromise=this.establishConnection();try{await this.connectionPromise,this.connectionStatus=CONNECTION_STATUS.CONNECTED}catch(error){throw this.connectionStatus=CONNECTION_STATUS.ERROR,error}finally{this.connectionPromise=null}}async establishConnection(){try{this.logger.info("Connecting to Dapr sidecar",{daprHost:this.daprHost,daprPort:this.daprPort,protocol:this.communicationProtocol});let protocols=dapr2().CommunicationProtocolEnum,useEndpointFromEnv=process.env[ENV_DAPR_HTTP_ENDPOINT]&&this.communicationProtocol===protocols.HTTP||process.env[ENV_DAPR_GRPC_ENDPOINT]&&this.communicationProtocol===protocols.GRPC,clientOptions={communicationProtocol:this.communicationProtocol,maxBodySizeMb:this.maxBodySizeMb,logger:{level:dapr2().LogLevel.Warn}};if(!useEndpointFromEnv)clientOptions.daprHost=this.daprHost,clientOptions.daprPort=this.daprPort;if(this.daprApiToken)clientOptions.daprApiToken=this.daprApiToken;await withTimeout(async()=>{this.client=new(dapr2()).DaprClient(clientOptions)},DEFAULT_CONNECTION_TIMEOUT_MS,"Connection to Dapr sidecar timed out"),await this.healthCheck(),this.logger.info("Successfully connected to Dapr sidecar")}catch(error){throw this.logger.error("Failed to connect to Dapr sidecar",error),this.client=null,createConnectionError(`Failed to connect to Dapr sidecar at ${this.daprHost}:${this.daprPort}`,error)}}async disconnect(){if(!this.client)return;try{this.logger.info("Disconnecting from Dapr sidecar"),this.client=null,this.connectionStatus=CONNECTION_STATUS.DISCONNECTED,this.logger.info("Disconnected from Dapr sidecar")}catch(error){throw this.logger.error("Error during disconnect",error),createConnectionError("Failed to disconnect from Dapr sidecar",error)}}isConnected(){return this.client!==null&&this.connectionStatus===CONNECTION_STATUS.CONNECTED}getConnectionStatus(){return this.connectionStatus}async healthCheck(){if(!this.client)throw createConnectionError("Not connected to Dapr sidecar");try{return await withTimeout(async()=>{if(!this.client)throw createConnectionError("Not connected to Dapr sidecar");let response=await this.client.invoker.invoke("healthz","healthz",dapr2().HttpMethod.GET);return{status:response.status===204?HEALTH_STATUS.HEALTHY:HEALTH_STATUS.UNHEALTHY,version:response.headers?.["dapr-version"]||"unknown"}},DEFAULT_HEALTH_CHECK_TIMEOUT_MS,"Health check timed out")}catch(error){return this.logger.error("Health check failed",error),{status:HEALTH_STATUS.UNHEALTHY,version:"unknown"}}}getClientConfig(){return{daprHost:this.daprHost,daprPort:this.daprPort,communicationProtocol:this.communicationProtocol,maxBodySizeMb:this.maxBodySizeMb,hasApiToken:!!this.daprApiToken,connectionStatus:this.connectionStatus}}}var cachedDapr2=null;var init_connection_manager=__esm(()=>{init_constants();init_error_handling();init_utils3()});var init_types2=()=>{};class DaprManager{connectionManager;logger;_state;_pubsub;_binding;_secret;_config;_invoke;_lock;_crypto;_workflow;constructor(options={}){this.logger=options.logger||createDefaultLogger(),this.connectionManager=new DaprConnectionManager(options);let clientProvider=async()=>{return this.connectionManager.getClient()};this._state=new DaprStateClient(clientProvider,this.logger),this._pubsub=new DaprPubSubClient(clientProvider,this.logger),this._binding=new DaprBindingClient(clientProvider,this.logger),this._secret=new DaprSecretClient(clientProvider,this.logger),this._config=new DaprConfigClient(clientProvider,this.logger),this._invoke=new DaprInvokeClient(clientProvider,this.logger),this._lock=new DaprLockClient(clientProvider,this.logger),this._crypto=new DaprCryptoClient(clientProvider,this.logger),this._workflow=new DaprWorkflowClient(clientProvider,this.logger)}async connect(){await this.connectionManager.connect()}async disconnect(){await this.connectionManager.disconnect()}isConnected(){return this.connectionManager.isConnected()}getConnectionStatus(){return this.connectionManager.getConnectionStatus()}async healthCheck(){return this.connectionManager.healthCheck()}getClientConfig(){return this.connectionManager.getClientConfig()}get state(){return this._state}get pubsub(){return this._pubsub}get binding(){return this._binding}get secret(){return this._secret}get config(){return this._config}get invoke(){return this._invoke}get lock(){return this._lock}get crypto(){return this._crypto}get workflow(){return this._workflow}}function getDaprManager(){if(!daprManagerInstance)daprManagerInstance=new DaprManager;return daprManagerInstance}var daprManagerInstance=null,daprManager;var init_Dapr=__esm(()=>{init_binding_client();init_config_client();init_crypto_client();init_invoke_client();init_lock_client();init_pubsub_client();init_secret_client();init_state_client();init_workflow_client();init_connection_manager();init_utils3();init_binding_client();init_config_client();init_crypto_client();init_invoke_client();init_lock_client();init_pubsub_client();init_secret_client();init_state_client();init_workflow_client();init_constants();init_error_handling();init_types2();daprManager=new Proxy({},{get(_target,property,receiver){let value=Reflect.get(getDaprManager(),property,receiver);return typeof value==="function"?value.bind(getDaprManager()):value},has(_target,property){return property in getDaprManager()}})});import Redis from"ioredis";class DirectRedisStore{client;constructor(client){this.client=client}async create(key,value,ttlSeconds){try{return{success:!0,data:ttlSeconds?await this.client.set(key,JSON.stringify(value),"EX",ttlSeconds):await this.client.set(key,JSON.stringify(value))}}catch(error){return{success:!1,error:error.message}}}async read(key){try{let raw=await this.client.get(key);return{success:!0,data:raw?JSON.parse(raw):null}}catch(error){return{success:!1,error:error.message}}}async update(key,value,preserveTtl=!0){try{return{success:!0,data:preserveTtl?await this.client.set(key,JSON.stringify(value),"KEEPTTL"):await this.client.set(key,JSON.stringify(value))}}catch(error){return{success:!1,error:error.message}}}async remove(key){try{return{success:!0,data:await this.client.del(key)}}catch(error){return{success:!1,error:error.message}}}async exists(key){try{return{success:!0,data:await this.client.exists(key)===1}}catch(error){return{success:!1,error:error.message}}}getClient(){return this.client}}class DaprRedisStore{storeName;keyPrefix;dapr;constructor(storeName,keyPrefix=""){this.storeName=storeName;this.keyPrefix=keyPrefix;this.dapr=new DaprManager}k(key){return this.keyPrefix+key}async create(key,value,ttlSeconds){try{let metadata=ttlSeconds?{ttlInSeconds:String(ttlSeconds)}:void 0;return await this.dapr.state.save([{key:this.k(key),value,metadata}],void 0,this.storeName),{success:!0,data:"OK"}}catch(error){return{success:!1,error:error.message}}}async read(key){try{return{success:!0,data:await this.dapr.state.get(this.k(key),this.storeName)??null}}catch(error){return{success:!1,error:error.message}}}async update(key,value,_preserveTtl=!0){try{return await this.dapr.state.save([{key:this.k(key),value}],void 0,this.storeName),{success:!0,data:"OK"}}catch(error){return{success:!1,error:error.message}}}async remove(key){try{return await this.dapr.state.delete(this.k(key),void 0,void 0,this.storeName),{success:!0,data:1}}catch(error){return{success:!1,error:error.message}}}async exists(key){try{let data=await this.dapr.state.get(this.k(key),this.storeName);return{success:!0,data:data!==void 0&&data!==null}}catch(error){return{success:!1,error:error.message}}}}class RedisManager{static instance=null;store;directClient=null;useDapr;constructor(config){if(RedisManager.instance){this.store=RedisManager.instance.store,this.directClient=RedisManager.instance.directClient,this.useDapr=RedisManager.instance.useDapr;return}if(!config)throw Error("Redis config must be provided for first initialization.");assertRedisConfig(config),this.useDapr=config.withDapr??!1;let keyPrefix=config.keyPrefix||"";if(config.withDapr)this.store=new DaprRedisStore(config.stateStoreName??"statestore",keyPrefix);else{let client=config.url?new Redis(config.url,keyPrefix?{keyPrefix}:{}):new Redis({host:config.host,port:config.port,...config.password?{password:config.password}:{},...config.username?{username:config.username}:{},...config.tls?{tls:{}}:{},...keyPrefix?{keyPrefix}:{}});this.directClient=client,this.store=new DirectRedisStore(client)}RedisManager.instance=this}static async reset(){let current=RedisManager.instance;if(RedisManager.instance=null,!current?.directClient)return;try{await current.directClient.quit()}catch{}}async create(key,value,ttlSeconds){return this.store.create(key,value,ttlSeconds)}async read(key){return this.store.read(key)}async update(key,value,preserveTtl=!0){return this.store.update(key,value,preserveTtl)}async remove(key){return this.store.remove(key)}async exists(key){return this.store.exists(key)}async readCounters(keys){return(await Promise.all(keys.map((k)=>this.read(k)))).map((r)=>{let v=r.success?r.data:null,n=typeof v==="number"?v:Number.parseFloat(String(v??""));return Number.isFinite(n)?n:0})}async incrementCounter(key,delta,ttlSeconds){if(!this.useDapr&&this.directClient){let v=await this.directClient.incrbyfloat(key,delta);if(ttlSeconds&&ttlSeconds>0)try{await this.directClient.expire(key,ttlSeconds)}catch{}return Number(v)}let cur=await this.read(key),raw=cur.success?cur.data:null,base=typeof raw==="number"?raw:Number.parseFloat(String(raw??"")),next=(Number.isFinite(base)?base:0)+delta;return await this.create(key,next,ttlSeconds),next}getDirectClient(){return this.directClient}async reauthenticate(username,password){if(this.directClient)await this.directClient.auth(username,password)}async keys(pattern){if(this.useDapr||!this.directClient)return logger.scoped("database.redis").warn("keys() not supported in Dapr mode",{pattern}),[];try{return await this.directClient.keys(pattern)}catch(error){return logger.scoped("database.redis").error("keys() failed",error,{pattern}),[]}}async acquireLock(lockKey,ttlSeconds=10){if(this.useDapr||!this.directClient){let existsResult=await this.exists(lockKey);if(!existsResult.success)return{success:!1,error:existsResult.error};if(existsResult.data)return{success:!0,data:!1};if((await this.create(lockKey,"1",ttlSeconds)).success)return{success:!0,data:!0};return{success:!1,error:"Failed to acquire lock"}}try{return{success:!0,data:await this.directClient.set(lockKey,"1","EX",ttlSeconds,"NX")==="OK"}}catch(error){return{success:!1,error:error.message}}}async releaseLock(lockKey){return this.remove(lockKey)}async waitForLock(lockKey,timeoutMs=5000,pollIntervalMs=50){let startTime=Date.now();while(Date.now()-startTime<timeoutMs){let existsResult=await this.exists(lockKey);if(!existsResult.success)return{success:!1,error:existsResult.error};if(!existsResult.data)return{success:!0,data:!0};await new Promise((resolve)=>setTimeout(resolve,pollIntervalMs))}return{success:!0,data:!1}}async getOrWait(key,timeoutMs=5000,pollIntervalMs=50){let startTime=Date.now();while(Date.now()-startTime<timeoutMs){let readResult=await this.read(key);if(!readResult.success)return{success:!1,error:readResult.error};if(readResult.data!==null)return{success:!0,data:readResult.data};await new Promise((resolve)=>setTimeout(resolve,pollIntervalMs))}return{success:!0,data:null}}}var assertRedisConfig=(config)=>{if(!config)throw Error("Redis config must be provided.");if(config.withDapr){if(!config.stateStoreName)throw Error("Dapr mode requires stateStoreName.");return}let hasUrl=Boolean(config.url),hasHostPort=Boolean(config.host)&&typeof config.port==="number";if(!hasUrl&&!hasHostPort)throw Error("Redis config requires either url or host and port.")};var init_Redis=__esm(()=>{init_Logger2();init_Dapr()});var init_Delete=__esm(()=>{init_Redis()});var init_Generate3=__esm(()=>{init_Redis();init_JWT()});var init_Read=__esm(()=>{init_Redis();init_JWT();init_Delete()});var init_Validate2=__esm(()=>{init_Read()});var init_RefreshToken=__esm(()=>{init_Delete();init_Generate3();init_Read();init_Validate2()});var DEFAULT_EXPIRY_SECONDS=86400,buildSessionKey=(sessionId)=>`session:${sessionId}`,serializeSession=(record)=>JSON.stringify(record),deserializeSession=(data)=>{if(!data)return null;if(typeof data==="object")return data;try{return JSON.parse(data)}catch{return null}};var deleteSession=async(options)=>{let manager=new RedisManager,key=buildSessionKey(options.sessionId),removeResult=await manager.remove(key);return removeResult.success&&removeResult.data>0},forgetSessionsInRedis=async(sessionIds)=>{for(let id of sessionIds){if(!id)continue;try{await deleteSession({sessionId:String(id)})}catch{}}};var init_Delete2=__esm(()=>{init_Redis()});import crypto4 from"crypto";var generateSession=async(options)=>{let manager=new RedisManager,sessionId=options.sessionId??crypto4.randomUUID(),now=Date.now(),nowIso=new Date(now).toISOString(),never=options.expiresInSeconds===null,ttlSeconds=never?void 0:options.expiresInSeconds??DEFAULT_EXPIRY_SECONDS,record={id:sessionId,userId:options.userId,createdAt:nowIso,expiresAt:never?null:new Date(now+ttlSeconds*1000).toISOString(),lastActiveAt:nowIso,clientMeta:options.clientMeta,fingerprintHash:options.fingerprintHash,deviceInfo:options.deviceInfo,refreshTokenHash:options.refreshTokenHash,loginMethod:options.loginMethod,rememberMe:options.rememberMe},writeResult=await manager.create(buildSessionKey(sessionId),serializeSession(record),ttlSeconds);if(!writeResult.success)return{success:!1,error:writeResult.error};return{success:!0,session:record}};var init_Generate4=__esm(()=>{init_Redis()});var init_Issue=__esm(()=>{init_JWT();init_Generate3();init_Delete2();init_Generate4()});var init_Session=__esm(()=>{init_Issue()});var readSession=async(options)=>{let manager=new RedisManager,key=buildSessionKey(options.sessionId),readResult=await manager.read(key);if(!readResult.success||!readResult.data)return null;let record=deserializeSession(readResult.data);if(!record)return null;if(record.expiresAt&&new Date(record.expiresAt).getTime()<=Date.now())return await deleteSession({sessionId:options.sessionId}),null;return record};var init_Read2=__esm(()=>{init_Redis();init_Delete2()});var updateSession=async(options)=>{let existing=await readSession({sessionId:options.sessionId});if(!existing)return{success:!1,error:"Session not found"};let updated={...existing,...options.updates,lastActiveAt:options.updates.lastActiveAt??new Date().toISOString()},manager=new RedisManager,remainingTtlSeconds=updated.expiresAt?Math.max(60,Math.ceil((new Date(updated.expiresAt).getTime()-Date.now())/1000)):void 0,writeResult=await manager.create(buildSessionKey(options.sessionId),serializeSession(updated),remainingTtlSeconds);if(!writeResult.success)return{success:!1,error:writeResult.error};return{success:!0,session:updated}},updateLastActiveAt=async(sessionId)=>{return updateSession({sessionId,updates:{lastActiveAt:new Date().toISOString()}})};var init_Update=__esm(()=>{init_Redis();init_Read2()});var validateSession=async(options)=>{let jwtResult=verifyJWT(options.jwtToken,options.jwtSecret);if(!jwtResult.valid)return{isValid:!1,reason:jwtResult.error};let session=await readSession({sessionId:options.sessionId});if(!session)return{isValid:!1,reason:"Session not found"};let fingerprintValid;if(options.savedFingerprint&&options.headers&&options.requestIp){let sanitizedHeaders={};for(let[key,value]of Object.entries(options.headers))if(value!==void 0)sanitizedHeaders[key]=value;let fingerprintResult=validateDeviceFingerprint({savedFingerprint:options.savedFingerprint,headers:sanitizedHeaders,requestIp:options.requestIp});if(fingerprintValid=fingerprintResult.isValid,!fingerprintResult.isValid)return{isValid:!1,reason:fingerprintResult.reason??"Fingerprint mismatch"}}return{isValid:!0,context:{userId:session.userId,sessionId:session.id,fingerprintValid}}};var init_Validate3=__esm(()=>{init_Validate();init_JWT();init_Read2()});var exports_SessionStore={};__export(exports_SessionStore,{validateSession:()=>validateSession,updateSession:()=>updateSession,updateLastActiveAt:()=>updateLastActiveAt,readSession:()=>readSession,generateSession:()=>generateSession,forgetSessionsInRedis:()=>forgetSessionsInRedis,deleteSession:()=>deleteSession});var init_SessionStore=__esm(()=>{init_Delete2();init_Generate4();init_Read2();init_Update();init_Validate3()});var init_Auth=__esm(()=>{init_Fingerprint();init_JWT();init_Password();init_RefreshToken();init_Session();init_SessionStore()});import{eq}from"drizzle-orm";function buildClaimAction(method,entity,field,relation,relationField,isBulk){let parts=[method.toLowerCase()];if(isBulk)parts.push("bulk");if(parts.push(entity),relation){if(parts.push("with"),parts.push(relation),relationField)parts.push(relationField)}else if(field)parts.push(field);return parts.join(".")}function buildClaimPath(entity,isBulk,hasId){if(isBulk)return`/${entity}/bulk`;if(hasId)return`/${entity}/:id`;return`/${entity}`}function generateEntityClaims(entity,config,schemaRelations){let claims=[],tableName=entity.table_name,excludedMethods=entity.excluded_methods||[];for(let method of HTTP_METHODS){if(excludedMethods.includes(method))continue;let needsId=method==="PUT"||method==="PATCH"||method==="DELETE";if(claims.push({action:buildClaimAction(method,tableName),description:`${method} access to ${tableName}`,path:buildClaimPath(tableName,!1,needsId&&method!=="DELETE"),method}),method==="GET"&&entity.columns){for(let column of entity.columns){if(config.skipColumns.includes(column.name))continue;claims.push({action:buildClaimAction(method,tableName,column.name),description:`${method} access to ${tableName}.${column.name}`,path:buildClaimPath(tableName),method})}let relationKey=`${tableName.replace(/_([a-z])/g,(_,l)=>l.toUpperCase())}Relations`;if(schemaRelations[relationKey]){let relationConfig=schemaRelations[relationKey];if(relationConfig?.config?.referencedTable?._?.name){let relationName=relationConfig.config.referencedTable._.name;claims.push({action:buildClaimAction(method,tableName,void 0,relationName),description:`${method} access to ${tableName} with ${relationName}`,path:buildClaimPath(tableName),method})}}}if(method==="POST"||method==="PUT"||method==="PATCH"){if(entity.columns)for(let column of entity.columns){if(config.skipColumns.includes(column.name))continue;claims.push({action:buildClaimAction(method,tableName,column.name),description:`${method} access to ${tableName}.${column.name}`,path:buildClaimPath(tableName,!1,method!=="POST"),method})}}}if(entity.bulk_endpoints_enabled===!0)for(let method of BULK_METHODS){if(excludedMethods.includes(method))continue;claims.push({action:buildClaimAction(method,tableName,void 0,void 0,void 0,!0),description:`Bulk ${method} access to ${tableName}`,path:buildClaimPath(tableName,!0),method})}return claims}async function seedClaims(db,schemaTables,schemaRelations,entities,config,logger2){let claimsTable=schemaTables.claims;if(!claimsTable)return logger2.warn("[Authorization] Claims table not found in schema"),{total:0,created:0,existing:0,claims:[]};let allClaims=[];for(let entity of entities){if(config.skipTables.includes(entity.table_name))continue;let entityClaims=generateEntityClaims(entity,config,schemaRelations);allClaims.push(...entityClaims)}let uniqueClaims=allClaims.filter((claim,index,self2)=>index===self2.findIndex((c)=>c.action===claim.action)),created=0,existing=0,claimActions=[];for(let claim of uniqueClaims)try{if((await db.select().from(claimsTable).where(eq(claimsTable.action,claim.action)).limit(1)).length===0)await db.insert(claimsTable).values(claim),created++,claimActions.push(claim.action),logger2.debug(`[Authorization] Created claim: ${claim.action}`);else existing++}catch(error){logger2.error(`[Authorization] Failed to create claim: ${claim.action}`,error)}return logger2.info(`[Authorization] Claims seeded: ${created} created, ${existing} existing, ${uniqueClaims.length} total`),{total:uniqueClaims.length,created,existing,claims:claimActions}}var HTTP_METHODS,BULK_METHODS;var init_ClaimSeeder=__esm(()=>{HTTP_METHODS=["GET","POST","PUT","PATCH","DELETE"],BULK_METHODS=["POST","PUT","DELETE"]});function parseStoredJson(stored){if(stored===null||stored===void 0)return null;if(typeof stored==="object")return stored;if(typeof stored==="string"){if(stored.length===0)return null;try{return JSON.parse(stored)}catch{return null}}if(typeof stored==="number"||typeof stored==="boolean")return stored;return null}import{eq as eq2,isNull,or}from"drizzle-orm";function activeRowsPredicate(table){let column=table?.isActive;if(!column)return;return or(isNull(column),eq2(column,!0))}var init_activeRows=()=>{};var exports_ClaimsCache={};__export(exports_ClaimsCache,{ClaimsCache:()=>ClaimsCache});import{and,eq as eq3}from"drizzle-orm";class ClaimsCache{prefix;redis;db;schemaTables;logger;constructor(config){this.prefix=config.prefix||DEFAULT_PREFIX,this.redis=config.redis,this.db=config.db,this.schemaTables=config.schemaTables,this.logger=config.logger}key(suffix){return`${this.prefix}:${suffix}`}async buildCache(){let rolesTable=this.schemaTables.roles,roleClaimsTable=this.schemaTables.roleClaims,claimsTable=this.schemaTables.claims;if(!rolesTable||!roleClaimsTable||!claimsTable)return this.logger.warn("[ClaimsCache] Required tables not found, skipping cache build"),{version:0,roleCount:0,totalMappings:0};let allRoles=await this.db.select().from(rolesTable),roleNames=[],totalMappings=0;for(let role of allRoles){let r=role,roleId=r.id,roleName=r.name;roleNames.push(roleName);let roleClaimRows=await this.db.select().from(roleClaimsTable).innerJoin(claimsTable,eq3(roleClaimsTable.claimId,claimsTable.id)).where(and(eq3(roleClaimsTable.roleId,roleId),activeRowsPredicate(roleClaimsTable))),claimActions=[];for(let row of roleClaimRows){let action=row.claims?.action;if(action)claimActions.push(action)}await this.redis.set(this.key(`role:${roleName}`),JSON.stringify(claimActions)),totalMappings+=claimActions.length}await this.redis.set(this.key("roles"),JSON.stringify(roleNames));let newVersion=storedVersionNumber(await this.redis.get(this.key("version")))+1;return await this.redis.set(this.key("version"),String(newVersion)),this.logger.info("[ClaimsCache] Cache built",{version:newVersion,roleCount:roleNames.length,totalMappings}),{version:newVersion,roleCount:roleNames.length,totalMappings}}async getVersion(){return storedVersionNumber(await this.redis.get(this.key("version")))}async resolveClaimsForRoles(roleNames){let allClaims=new Set;for(let roleName of roleNames){let claims=parseStoredJson(await this.redis.get(this.key(`role:${roleName}`)));if(Array.isArray(claims))for(let c of claims)allClaims.add(c);else if(claims!==null)this.logger.warn("[ClaimsCache] Cached role entry unreadable, ignoring",{roleName})}return Array.from(allClaims)}async invalidate(){return(await this.buildCache()).version}getPrefix(){return this.prefix}}var DEFAULT_PREFIX="nucleus:claims",storedVersionNumber=(stored)=>{let value=parseStoredJson(stored),parsed=typeof value==="number"?value:Number.parseInt(String(value??""),10);return Number.isFinite(parsed)?parsed:0};var init_ClaimsCache=__esm(()=>{init_activeRows()});var DEFAULT_AUTHORIZATION_CONFIG,AUTHORIZATION_TABLE_KEYS,GODMIN_ROLE_NAME="godmin";var init_types3=__esm(()=>{DEFAULT_AUTHORIZATION_CONFIG={enabled:!1,autoSeedClaims:!0,skipTables:["audit_logs"],skipColumns:["id","created_at","updated_at","is_active","password","version"],excludedPaths:[],publicPaths:["/auth/login","/auth/register"]},AUTHORIZATION_TABLE_KEYS={users:"users",roles:"roles",claims:"claims",userRoles:"userRoles",roleClaims:"roleClaims"}});var{password}=globalThis.Bun;import{and as and2,eq as eq4}from"drizzle-orm";async function setupGodmin(db,schemaTables,config,logger2){if(!config.godminEmail||!config.godminPassword)return logger2.warn("[Authorization] Godmin email or password not configured, skipping godmin setup"),{success:!1};let{roles:rolesTable,users:usersTable,userRoles:userRolesTable}=schemaTables;if(!rolesTable||!usersTable||!userRolesTable)return logger2.error("[Authorization] Required tables not found for godmin setup"),{success:!1};try{let roleId,existingRole=await db.select().from(rolesTable).where(eq4(rolesTable.name,GODMIN_ROLE_NAME)).limit(1);if(existingRole.length===0){let[newRole]=await db.insert(rolesTable).values({name:GODMIN_ROLE_NAME,description:"God mode administrator - bypasses all authorization checks"}).returning();roleId=newRole.id,logger2.info(`[Authorization] Created godmin role: ${roleId}`)}else roleId=existingRole[0].id,logger2.debug(`[Authorization] Godmin role already exists: ${roleId}`);let userId,existingUser=await db.select().from(usersTable).where(eq4(usersTable.email,config.godminEmail)).limit(1);if(existingUser.length===0){let hashedPassword=await password.hash(config.godminPassword,{algorithm:"bcrypt",cost:10}),[newUser]=await db.insert(usersTable).values({email:config.godminEmail,password:hashedPassword,verifiedAt:new Date,isActive:!0,isGod:!0}).returning();userId=newUser.id,logger2.info(`[Authorization] Created godmin user: ${userId}`)}else{if(userId=existingUser[0].id,!existingUser[0].isGod)await db.update(usersTable).set({isGod:!0}).where(eq4(usersTable.id,userId)),logger2.info(`[Authorization] Marked existing godmin user as isGod=true: ${userId}`);logger2.debug(`[Authorization] Godmin user already exists: ${userId}`)}if(!((await db.select().from(userRolesTable).where(and2(eq4(userRolesTable.userId,userId),eq4(userRolesTable.roleId,roleId))).limit(1)).length>0))await db.insert(userRolesTable).values({userId,roleId}),logger2.info(`[Authorization] Assigned godmin role to user: ${userId}`);return{success:!0,userId,roleId}}catch(error){return logger2.error("[Authorization] Failed to setup godmin",error),{success:!1}}}function isGodminRole(roleName){return roleName===GODMIN_ROLE_NAME}var init_GodminSetup=__esm(()=>{init_types3()});import{and as and3,eq as eq5,inArray,sql}from"drizzle-orm";function isSelfReference(value){return value.startsWith(SELF_PREFIX)}function parseSelfReference(value){return{field:value.slice(SELF_PREFIX.length)}}function parseScopeWithSelf(scope){if(!scope)return{};let params=new URLSearchParams(scope),result={};for(let[key,value]of params.entries())if(isSelfReference(value))result[key]=parseSelfReference(value);else result[key]=value;return result}function resolveScopeWithSelf(parsedScope,userData,logger2){let resolved={},unresolved=[];for(let[key,value]of Object.entries(parsedScope))if(typeof value==="object"&&"field"in value){if(!userData){logger2.warn(`[Authorization] Cannot resolve self:${value.field} - userData not provided`),unresolved.push(key);continue}let lookup=lookupUserDataField(userData,value.field);if(!lookup.found){logger2.warn(`[Authorization] Cannot resolve self:${value.field} - field not found in userData`),unresolved.push(key);continue}resolved[key]=lookup.value,logger2.debug(`[Authorization] Resolved self:${value.field} -> ${String(lookup.value)}`)}else resolved[key]=value;return{resolved,unresolved}}function resolveClaimScopes(rows,userData,logger2){let claimScopes={},dropped=new Set,unrestricted=new Set;for(let{action,scope}of rows){if(!scope){unrestricted.add(action);continue}if(!scope.includes("="))continue;let parsed=parseScopeWithSelf(scope),{resolved,unresolved}=resolveScopeWithSelf(parsed,userData,logger2);if(unresolved.length>0){dropped.add(action);continue}claimScopes[action]={...claimScopes[action]??{},...resolved}}for(let a of unrestricted)delete claimScopes[a],dropped.delete(a);for(let a of dropped)delete claimScopes[a];return{claimScopes,dropped:Array.from(dropped)}}function mergeGrantingScopes(grantingActions,claimScopes){if(!claimScopes)return;let merged={},any=!1;for(let action of grantingActions){let s=claimScopes[action];if(!s||Object.keys(s).length===0)return;Object.assign(merged,s),any=!0}return any?merged:void 0}function buildClaimPattern(method,entity,field,relation){let parts=[method.toLowerCase(),entity];if(relation)parts.push("with",relation);else if(field)parts.push(field);return parts.join(".")}function claimMatches(userClaim,requiredPattern,requireSpecificity=!1){if(userClaim===requiredPattern)return!0;let userParts=userClaim.split("."),requiredParts=requiredPattern.split(".");if(userParts.length>requiredParts.length)return!1;if(requireSpecificity&&userParts.length<2&&requiredParts.length>=2)return!1;for(let i=0;i<userParts.length;i++)if(userParts[i]!==requiredParts[i])return!1;return!0}async function checkAuthorization(params){let{userId,method,entity,requestedFields,requestedRelations,db,schemaTables,logger:logger2,getUserData}=params,reqSpec=params.requireClaimSpecificity??!1,userData=params.userData,ensureUserData=async()=>{if(userData!==void 0)return;if(getUserData)try{userData=await getUserData()}catch(err){logger2.warn("[Authorization] getUserData callback failed",{userId,error:err instanceof Error?err.message:String(err)})}},rolesTable=schemaTables[AUTHORIZATION_TABLE_KEYS.roles],userRolesTable=schemaTables[AUTHORIZATION_TABLE_KEYS.userRoles],roleClaimsTable=schemaTables[AUTHORIZATION_TABLE_KEYS.roleClaims],claimsTable=schemaTables[AUTHORIZATION_TABLE_KEYS.claims];if(!rolesTable||!userRolesTable||!roleClaimsTable||!claimsTable)return logger2.error("[Authorization] Required tables not found"),{authorized:!1,reason:"Authorization tables not configured"};try{let userRolesCols=userRolesTable,rolesCols=rolesTable,userRoles=await db.select({roleId:userRolesCols.roleId,roleName:rolesCols.name}).from(userRolesTable).innerJoin(rolesTable,eq5(userRolesCols.roleId,rolesCols.id)).where(and3(eq5(userRolesCols.userId,userId),activeRowsPredicate(userRolesTable)));if(userRoles.length===0)return{authorized:!1,reason:"User has no roles assigned"};if(userRoles.some((ur)=>isGodminRole(ur.roleName)))return logger2.debug(`[Authorization] User ${userId} has godmin role, bypassing checks`),{authorized:!0};let roleIds=userRoles.map((ur)=>ur.roleId),roleClaimsCols=roleClaimsTable,claimsCols=claimsTable,roleClaims=await db.select({claimAction:claimsCols.action,scope:roleClaimsCols.scope}).from(roleClaimsTable).innerJoin(claimsTable,eq5(roleClaimsCols.claimId,claimsCols.id)).where(and3(inArray(roleClaimsCols.roleId,roleIds),activeRowsPredicate(roleClaimsTable)));if(roleClaims.length===0)return{authorized:!1,reason:"User roles have no claims assigned"};let entityClaimPattern=buildClaimPattern(method,entity),hasEntityAccess=roleClaims.some((rc)=>claimMatches(rc.claimAction,entityClaimPattern,reqSpec)),allowedFields=[],allowedRelations=[],scopeFilters={},unresolvedSelf=[],fieldPatterns=(requestedFields??[]).map((field)=>({field,pattern:buildClaimPattern(method,entity,field)})),relationPatterns=(requestedRelations??[]).map((relation)=>({relation,pattern:buildClaimPattern(method,entity,void 0,relation)})),claimCouldGrant=(action)=>claimMatches(action,entityClaimPattern,reqSpec)||fieldPatterns.some((f)=>claimMatches(action,f.pattern,reqSpec))||relationPatterns.some((r)=>claimMatches(action,r.pattern,reqSpec));if(roleClaims.some((rc)=>{let scope=rc.scope;return!!scope&&scope.includes("self:")&&claimCouldGrant(rc.claimAction)}))await ensureUserData();let applyClaimScope=(rc)=>{let parsedScope=parseScopeWithSelf(rc.scope),{resolved,unresolved}=resolveScopeWithSelf(parsedScope,userData,logger2);Object.assign(scopeFilters,resolved),unresolvedSelf.push(...unresolved)},denyOnUnresolvedSelf=()=>{if(unresolvedSelf.length===0)return null;return logger2.warn("[Authorization] Denying request: unresolvable self: scope (failing closed)",{userId,method,entity,unresolved:unresolvedSelf}),{authorized:!1,reason:"Ownership scope could not be resolved"}};if(hasEntityAccess){let unrestricted=!1;for(let rc of roleClaims){if(!claimMatches(rc.claimAction,entityClaimPattern,reqSpec))continue;if(!rc.scope){unrestricted=!0;continue}applyClaimScope(rc)}if(unrestricted)return{authorized:!0};let denied=denyOnUnresolvedSelf();if(denied)return denied;return{authorized:!0,scopeFilters:Object.keys(scopeFilters).length>0?scopeFilters:void 0}}let unrestrictedField=!1;for(let{field,pattern}of fieldPatterns){let granting=roleClaims.filter((rc)=>claimMatches(rc.claimAction,pattern,reqSpec));if(granting.length>0)if(allowedFields.push(field),granting.some((rc)=>!rc.scope))unrestrictedField=!0;else for(let rc of granting)applyClaimScope(rc)}for(let{relation,pattern}of relationPatterns){let granting=roleClaims.filter((rc)=>claimMatches(rc.claimAction,pattern,reqSpec));if(granting.length>0)if(allowedRelations.push(relation),granting.some((rc)=>!rc.scope))unrestrictedField=!0;else for(let rc of granting)applyClaimScope(rc)}if(!unrestrictedField){let denied=denyOnUnresolvedSelf();if(denied)return denied}if(!(allowedFields.length>0||allowedRelations.length>0))return{authorized:!1,reason:`No access to ${method} ${entity}`};return{authorized:!0,allowedFields:allowedFields.length>0?allowedFields:["id"],allowedRelations,scopeFilters:!unrestrictedField&&Object.keys(scopeFilters).length>0?scopeFilters:void 0}}catch(error){return logger2.error("[Authorization] Check failed",error),{authorized:!1,reason:"Authorization check failed"}}}function checkAuthorizationFromJWT(params){let{userClaims,userRoles,method,entity,requestedFields,requestedRelations,logger:logger2}=params,reqSpec=params.requireClaimSpecificity??!1,claimScopes=params.claimScopes;if(userClaims.length===0&&userRoles.length===0)return{authorized:!1,reason:"No roles or claims in token"};if(userRoles.some((r)=>isGodminRole(r)))return logger2.debug("[Authorization:JWT] User has godmin role, bypassing checks"),{authorized:!0};let entityClaimPattern=buildClaimPattern(method,entity),entityGranting=userClaims.filter((c)=>claimMatches(c,entityClaimPattern,reqSpec));if(entityGranting.length>0){let scopeFilters2=mergeGrantingScopes(entityGranting,claimScopes);return{authorized:!0,...scopeFilters2?{scopeFilters:scopeFilters2}:{}}}let allowedFields=[],allowedRelations=[],grantingActions=[];if(requestedFields)for(let field of requestedFields){let fieldPattern=buildClaimPattern(method,entity,field),granting=userClaims.filter((c)=>claimMatches(c,fieldPattern,reqSpec));if(granting.length>0)allowedFields.push(field),grantingActions.push(...granting)}if(requestedRelations)for(let relation of requestedRelations){let relationPattern=buildClaimPattern(method,entity,void 0,relation),granting=userClaims.filter((c)=>claimMatches(c,relationPattern,reqSpec));if(granting.length>0)allowedRelations.push(relation),grantingActions.push(...granting)}if(!(allowedFields.length>0||allowedRelations.length>0))return{authorized:!1,reason:`No access to ${method} ${entity}`};let scopeFilters=mergeGrantingScopes(grantingActions,claimScopes);return{authorized:!0,allowedFields:allowedFields.length>0?allowedFields:["id"],allowedRelations,...scopeFilters?{scopeFilters}:{}}}async function checkAuthorizationViaIDP(params){let{idpUrl,accessToken,method,entity,requestedFields,requestedRelations,logger:logger2}=params;try{let response=await fetch(`${idpUrl}/auth/check`,{method:"POST",headers:{"Content-Type":"application/json",Cookie:`access_token=${accessToken}`},body:JSON.stringify({entity,method,fields:requestedFields,relations:requestedRelations})});if(!response.ok)return logger2.warn(`[Authorization:IDP] IDP /auth/check returned ${response.status}`),{authorized:!1,reason:`IDP authorization check failed (${response.status})`};let payload=await response.json();return unwrapIdpCheckResponse(payload)}catch(error){let msg=error instanceof Error?error.message:String(error);return logger2.error(`[Authorization:IDP] Failed to reach IDP: ${msg}`),{authorized:!1,reason:"IDP authorization service unavailable"}}}function filterResponseFields(data,allowedFields){if(!allowedFields||allowedFields.length===0)return data;let fieldsToInclude=[...new Set([...["id"],...allowedFields])],toCamel=(value)=>value.replace(/_([a-z])/g,(_,letter)=>letter.toUpperCase()),allowedKeys=new Set;for(let field of fieldsToInclude)allowedKeys.add(field),allowedKeys.add(toCamel(field));let filterSingle=(item)=>{let filtered={};for(let key of Object.keys(item))if(allowedKeys.has(key))filtered[key]=item[key];return filtered};if(Array.isArray(data))return data.map(filterSingle);return filterSingle(data)}function filterResponseRelations(data,allowedRelations){if(!allowedRelations)return data;let filterSingle=(item)=>{let filtered={...item};for(let key of Object.keys(filtered))if(typeof filtered[key]==="object"&&filtered[key]!==null&&!allowedRelations.includes(key))delete filtered[key];return filtered};if(Array.isArray(data))return data.map(filterSingle);return filterSingle(data)}function buildScopeConditions(scopeFilters,resolveColumn){let conditions=[],unresolvedFields=[];if(!scopeFilters)return{conditions,unresolvedFields};for(let[field,value]of Object.entries(scopeFilters)){let col=resolveColumn(field);if(col)conditions.push(eq5(col,value));else unresolvedFields.push(field),conditions.push(sql`1 = 0`)}return{conditions,unresolvedFields}}var SELF_PREFIX="self:",toCamelCase2=(value)=>value.replace(/_([a-z])/g,(_,c)=>c.toUpperCase()),toSnakeCase=(value)=>value.replace(/([A-Z])/g,(_,c)=>`_${c.toLowerCase()}`),lookupUserDataField=(userData,fieldName)=>{if(fieldName in userData)return{found:!0,value:userData[fieldName]};let camel=toCamelCase2(fieldName);if(camel!==fieldName&&camel in userData)return{found:!0,value:userData[camel]};let snake=toSnakeCase(fieldName);if(snake!==fieldName&&snake in userData)return{found:!0,value:userData[snake]};return{found:!1}},unwrapIdpCheckResponse=(payload)=>{if(!payload||typeof payload!=="object")return{authorized:!1,reason:"IDP returned malformed response"};let envelope=payload;if(envelope.data&&typeof envelope.data==="object"){let data=envelope.data;if(typeof data.authorized==="boolean")return data}let flat=payload;if(typeof flat.authorized==="boolean")return flat;return{authorized:!1,reason:"IDP returned unrecognised response shape"}};var init_Middleware=__esm(()=>{init_activeRows();init_GodminSetup();init_types3()});var exports_SeedRunner={};__export(exports_SeedRunner,{runSeed:()=>runSeed,expandClaimPatterns:()=>expandClaimPatterns});import{and as and4,eq as eq6}from"drizzle-orm";function expandClaimPatterns(patterns,allActions){let out=new Set;for(let pattern of patterns)if(pattern.endsWith(".*")){let prefix=pattern.slice(0,-2);for(let action of allActions)if(action===prefix||action.startsWith(`${prefix}.`))out.add(action)}else out.add(pattern);return[...out]}async function runSeed(db,schemaTables,seedConfig,logger2){let{roles:rolesTable,claims:claimsTable,roleClaims:roleClaimsTable}=schemaTables,result={rolesCreated:0,rolesExisting:0,claimsCreated:0,claimsExisting:0,assignmentsCreated:0,assignmentsExisting:0,assignmentsUpdated:0};if(seedConfig.roles?.length&&rolesTable)for(let roleDef of seedConfig.roles)try{if((await db.select().from(rolesTable).where(eq6(rolesTable.name,roleDef.name)).limit(1)).length===0)await db.insert(rolesTable).values({name:roleDef.name,description:roleDef.description||""}),result.rolesCreated++,logger2.info(`[Seed] Created role: ${roleDef.name}`);else result.rolesExisting++}catch(error){logger2.error(`[Seed] Failed to seed role: ${roleDef.name}`,error)}if(seedConfig.claims?.length&&claimsTable)for(let claimDef of seedConfig.claims)try{let existing=await db.select().from(claimsTable).where(eq6(claimsTable.action,claimDef.action)).limit(1);if(existing.length===0)await db.insert(claimsTable).values({action:claimDef.action,path:claimDef.path,method:claimDef.method,description:claimDef.description||`${claimDef.method} ${claimDef.path}`,...claimDef.policy!==void 0?{policy:claimDef.policy}:{}}),result.claimsCreated++,logger2.info(`[Seed] Created claim: ${claimDef.action}`);else if(claimDef.policy!==void 0){let existingRow=existing[0],currentPolicy=JSON.stringify(existingRow.policy??null),desiredPolicy=JSON.stringify(claimDef.policy??null);if(currentPolicy!==desiredPolicy)await db.update(claimsTable).set({policy:claimDef.policy}).where(eq6(claimsTable.action,claimDef.action)),result.claimsExisting++,logger2.warn(`[Seed] Reconciled policy for claim: ${claimDef.action}`);else result.claimsExisting++}else result.claimsExisting++}catch(error){logger2.error(`[Seed] Failed to seed claim: ${claimDef.action}`,error)}if(seedConfig.roleClaimAssignments?.length&&rolesTable&&claimsTable&&roleClaimsTable){let allClaimActions=(await db.select().from(claimsTable)).map((c)=>String(c.action??""));for(let assignment of seedConfig.roleClaimAssignments){let role=(await db.select().from(rolesTable).where(eq6(rolesTable.name,assignment.role)).limit(1))[0];if(!role){logger2.warn(`[Seed] Role not found for assignment: ${assignment.role}`);continue}let roleId=role.id,resolvedActions=expandClaimPatterns(assignment.claims,allClaimActions);for(let pattern of assignment.claims)if(pattern.endsWith(".*")&&!resolvedActions.some((a)=>a.startsWith(pattern.slice(0,-1))))logger2.warn(`[Seed] No claim matched prefix pattern: ${pattern}`);for(let claimAction of resolvedActions)try{let claim=(await db.select().from(claimsTable).where(eq6(claimsTable.action,claimAction)).limit(1))[0];if(!claim){logger2.warn(`[Seed] Claim not found for assignment: ${claimAction}`);continue}let claimId=claim.id,existingAssignment=await db.select().from(roleClaimsTable).where(and4(eq6(roleClaimsTable.roleId,roleId),eq6(roleClaimsTable.claimId,claimId))).limit(1);if(existingAssignment.length===0)await db.insert(roleClaimsTable).values({roleId,claimId,scope:assignment.scope||null}),result.assignmentsCreated++;else{let existingRow=existingAssignment[0],desiredScope=assignment.scope||null,currentScope=existingRow.scope??null;if(currentScope!==desiredScope)await db.update(roleClaimsTable).set({scope:desiredScope}).where(and4(eq6(roleClaimsTable.roleId,roleId),eq6(roleClaimsTable.claimId,claimId))),result.assignmentsUpdated++,logger2.warn(`[Seed] Reconciled scope for ${assignment.role} -> ${claimAction}: ${JSON.stringify(currentScope)} => ${JSON.stringify(desiredScope)}`);else result.assignmentsExisting++}}catch(error){logger2.error(`[Seed] Failed to assign claim ${claimAction} to role ${assignment.role}`,error)}if(result.assignmentsCreated>0)logger2.info(`[Seed] Role "${assignment.role}": assigned ${result.assignmentsCreated} claims`)}}return result}var init_SeedRunner=()=>{};var init_Authorization=__esm(()=>{init_ClaimSeeder();init_ClaimsCache();init_GodminSetup();init_Middleware();init_SeedRunner();init_types3()});function parseField(raw,spec){let out=new Set;for(let part of raw.split(",")){if(part==="")return null;let[rangePart,stepPart,...extra]=part.split("/");if(extra.length>0||rangePart===void 0)return null;let step=1;if(stepPart!==void 0){if(!/^\d+$/.test(stepPart))return null;if(step=Number.parseInt(stepPart,10),step<1)return null}let from,to;if(rangePart==="*")from=spec.min,to=spec.max;else if(rangePart.includes("-")){let[a,b,...rest]=rangePart.split("-");if(rest.length>0||!isIntInRange(a,spec)||!isIntInRange(b,spec))return null;if(from=namedToNumber(a,spec),to=namedToNumber(b,spec),from>to)return null}else{if(!isIntInRange(rangePart,spec))return null;from=namedToNumber(rangePart,spec),to=stepPart===void 0?from:spec.max}for(let v=from;v<=to;v+=step)out.add(v)}return out.size>0?out:null}function isIntInRange(value,spec){if(value===void 0)return!1;let n=namedToNumber(value,spec);return n!==null&&n>=spec.min&&n<=spec.max}function namedToNumber(value,spec){if(/^\d+$/.test(value))return Number.parseInt(value,10);let lower=value.toLowerCase();if(spec===MONTH){let i=MONTH_NAMES.indexOf(lower);return i===-1?null:i+1}if(spec===WEEKDAY){let i=DAY_NAMES.indexOf(lower);return i===-1?null:i}return null}function parseCron(expression){let trimmed=expression.trim(),parts=(MACROS[trimmed.toLowerCase()]??trimmed).split(/\s+/);if(parts.length!==5)return null;let[minRaw,hourRaw,dayRaw,monthRaw,weekdayRaw]=parts,minute=parseField(minRaw,MINUTE),hour=parseField(hourRaw,HOUR),day=parseField(dayRaw,DAY),month=parseField(monthRaw,MONTH),weekdayRawSet=parseField(weekdayRaw,WEEKDAY);if(!minute||!hour||!day||!month||!weekdayRawSet)return null;let weekday=new Set([...weekdayRawSet].map((d)=>d===7?0:d));return{minute,hour,day,month,weekday,dayUnrestricted:dayRaw==="*",weekdayUnrestricted:weekdayRaw==="*"}}function formatterFor(timeZone){let cached=formatterCache.get(timeZone);if(cached)return cached;try{let fmt=new Intl.DateTimeFormat("en-US",{timeZone,hour12:!1,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",weekday:"short"});return formatterCache.set(timeZone,fmt),fmt}catch{return null}}function partsIn(ts,fmt){let parts=fmt.formatToParts(new Date(ts)),get=(type)=>parts.find((p)=>p.type===type)?.value??"0",hour=Number.parseInt(get("hour"),10)%24;return{year:Number.parseInt(get("year"),10),month:Number.parseInt(get("month"),10),day:Number.parseInt(get("day"),10),hour,minute:Number.parseInt(get("minute"),10),weekday:WEEKDAY_INDEX[get("weekday")]??0}}function offsetMsAt(ts,fmt){let p=partsIn(ts,fmt);return Date.UTC(p.year,p.month-1,p.day,p.hour,p.minute,new Date(ts).getUTCSeconds())-Math.floor(ts/1000)*1000}function zonedWallTimeToInstant(year,month,day,hour,minute,fmt){let naive=Date.UTC(year,month-1,day,hour,minute,0,0),ts=naive-offsetMsAt(naive,fmt),corrected=naive-offsetMsAt(ts,fmt);if(corrected!==ts)ts=corrected;let target=stamp(year,month,day,hour,minute),localStamp=(at)=>{let p=partsIn(at,fmt);return stamp(p.year,p.month,p.day,p.hour,p.minute)};if(localStamp(ts)===target)return ts;let probe=Math.min(ts,naive-offsetMsAt(naive,fmt));for(let i=0;i<=240;i++){if(localStamp(probe)>=target)return probe;probe+=60000}return ts}function stamp(year,month,day,hour,minute){return((year*100+month)*100+day)*1e4+hour*100+minute}function dayMatches(fields,wall){if(!fields.month.has(wall.month))return!1;let domOk=fields.day.has(wall.day),dowOk=fields.weekday.has(wall.weekday);if(fields.dayUnrestricted&&fields.weekdayUnrestricted)return!0;if(fields.dayUnrestricted)return dowOk;if(fields.weekdayUnrestricted)return domOk;return domOk||dowOk}function nextCronRun(expression,from=new Date,timeZone="UTC"){let fields=parseCron(expression);if(!fields)return null;let fmt=formatterFor(timeZone)??formatterFor("UTC");if(!fmt)return null;let hours=[...fields.hour].sort((a,b)=>a-b),minutes=[...fields.minute].sort((a,b)=>a-b),fromTs=from.getTime();if(!Number.isFinite(fromTs))return null;let cursor=partsIn(fromTs,fmt);for(let dayIndex=0;dayIndex<2929;dayIndex++){if(dayMatches(fields,cursor))for(let hour of hours)for(let minute of minutes){let ts=zonedWallTimeToInstant(cursor.year,cursor.month,cursor.day,hour,minute,fmt);if(ts>fromTs)return new Date(ts)}let nextDayUtc=Date.UTC(cursor.year,cursor.month-1,cursor.day+1,12,0,0),probe=new Date(nextDayUtc);cursor={year:probe.getUTCFullYear(),month:probe.getUTCMonth()+1,day:probe.getUTCDate(),hour:0,minute:0,weekday:probe.getUTCDay()}}return null}var MINUTE,HOUR,DAY,MONTH,WEEKDAY,MONTH_NAMES,DAY_NAMES,MACROS,formatterCache,WEEKDAY_INDEX;var init_cron=__esm(()=>{MINUTE={min:0,max:59},HOUR={min:0,max:23},DAY={min:1,max:31},MONTH={min:1,max:12},WEEKDAY={min:0,max:7};MONTH_NAMES=["jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"],DAY_NAMES=["sun","mon","tue","wed","thu","fri","sat"];MACROS={"@yearly":"0 0 1 1 *","@annually":"0 0 1 1 *","@monthly":"0 0 1 * *","@weekly":"0 0 * * 0","@daily":"0 0 * * *","@midnight":"0 0 * * *","@hourly":"0 * * * *"};formatterCache=new Map;WEEKDAY_INDEX={Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6}});import{createCipheriv,createDecipheriv,randomBytes as randomBytes2,scryptSync}from"crypto";var MAGIC,IV_LEN=12,TAG_LEN=16,deriveKey=(secret)=>scryptSync(secret,"nucleus-backup-v1",32),encryptBackup=(plaintext,secret)=>{if(!secret)throw Error("backup encryption key is empty");let key=deriveKey(secret),iv=randomBytes2(IV_LEN),cipher=createCipheriv("aes-256-gcm",key,iv),ciphertext=Buffer.concat([cipher.update(plaintext,"utf-8"),cipher.final()]),tag=cipher.getAuthTag();return Buffer.concat([MAGIC,iv,tag,ciphertext])},isEncryptedBackup=(buf)=>buf.length>=MAGIC.length+IV_LEN+TAG_LEN&&buf.subarray(0,MAGIC.length).equals(MAGIC),decryptBackup=(blob,secret)=>{if(!secret)throw Error("backup encryption key is empty");if(!isEncryptedBackup(blob))throw Error("not an encrypted backup");let key=deriveKey(secret),iv=blob.subarray(MAGIC.length,MAGIC.length+IV_LEN),tag=blob.subarray(MAGIC.length+IV_LEN,MAGIC.length+IV_LEN+TAG_LEN),ciphertext=blob.subarray(MAGIC.length+IV_LEN+TAG_LEN),decipher=createDecipheriv("aes-256-gcm",key,iv);return decipher.setAuthTag(tag),Buffer.concat([decipher.update(ciphertext),decipher.final()]).toString("utf-8")};var init_encryption=__esm(()=>{MAGIC=Buffer.from("NXB1")});import{mkdir as mkdir3,readFile,stat as stat2,unlink as unlink3,writeFile}from"fs/promises";import{join as join4}from"path";import{eq as eq7,getTableColumns,sql as sql2}from"drizzle-orm";function nextHopMs(delayMs){if(!Number.isFinite(delayMs)||delayMs<=0)return 0;return Math.min(delayMs,MAX_TIMEOUT_MS)}function reviveRowTypes(table,rows){let columns;try{columns=getTableColumns(table)}catch{return rows}let dateColumns=Object.entries(columns).filter(([,col2])=>col2?.dataType==="date").map(([name])=>name);if(dateColumns.length===0)return rows;return rows.map((row)=>{let copy=null;for(let name of dateColumns){let value=row[name];if(typeof value!=="string")continue;let parsed=new Date(value);if(Number.isNaN(parsed.getTime()))continue;if(!copy)copy={...row};copy[name]=parsed}return copy??row})}function normalizeTableName(name){return name.replace(/[^a-z0-9]/gi,"").toLowerCase()}function selectBackupTables(tables,excludeTables){let excluded=new Set(excludeTables.map(normalizeTableName));return Object.keys(tables).filter((name)=>{if(excluded.has(normalizeTableName(name)))return!1;let val=tables[name];if(!val||typeof val!=="object")return!1;return Object.getOwnPropertySymbols(val).length>0})}class BackupService{db;logger;config;schemaTables;schemaName;backupLogsTable;cronTimer=null;schedulerActive=!1;lock;constructor(serviceConfig){this.db=serviceConfig.db,this.logger=serviceConfig.logger,this.config=serviceConfig.config,this.schemaTables=serviceConfig.schemaTables,this.schemaName=serviceConfig.schemaName,this.backupLogsTable=serviceConfig.backupLogsTable,this.lock=serviceConfig.lock}async createBackup(trigger="manual",performedBy,targetSchemaName,targetSchemaTables){let resolvedSchema=targetSchemaName||this.schemaName,resolvedTables=targetSchemaTables||this.schemaTables,now=new Date,backupId=crypto.randomUUID(),timestamp=now.toISOString().replace(/[:.]/g,"-"),backupName=`${resolvedSchema}_${timestamp}`,fileName=`${backupName}.json`,filePath=join4(this.config.storagePath,fileName),logRecord={id:backupId,backupName,fileName,schemaName:resolvedSchema,format:this.config.format,status:"running",trigger,sizeBytes:null,tableCount:null,rowCount:null,includedTables:[],excludedTables:this.config.excludeTables,errorMessage:null,startedAt:now.toISOString(),completedAt:null,performedBy:performedBy||null,cronExpression:trigger==="scheduled"?this.config.schedule.cron:null,retentionDays:this.config.schedule.retentionDays};await this.insertLogRecord(logRecord);try{await mkdir3(this.config.storagePath,{recursive:!0});let tableNames=this.getBackupTableNames(resolvedTables),backupData=[],totalRows=0;for(let tableName of tableNames){let table=resolvedTables[tableName];if(!table)continue;try{let rows=await this.db.select().from(table),columns=Object.keys(table).filter((k)=>!k.startsWith("_")&&typeof table[k]!=="function");backupData.push({tableName,columns,rows}),totalRows+=rows.length}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.warn(`[Backup] Failed to export table ${tableName}: ${msg}`)}}let backupFile={manifest:{version:"1.0",createdAt:now.toISOString(),schemaName:resolvedSchema,format:this.config.format,tables:backupData.map((t)=>({tableName:t.tableName,rowCount:t.rows.length,columns:t.columns})),totalRows},data:backupData},jsonContent=JSON.stringify(backupFile,null,2);if(this.config.encryptionKey)await writeFile(filePath,encryptBackup(jsonContent,this.config.encryptionKey));else await writeFile(filePath,jsonContent,"utf-8");let fileStats=await stat2(filePath);return logRecord.status="completed",logRecord.completedAt=new Date().toISOString(),logRecord.tableCount=backupData.length,logRecord.rowCount=totalRows,logRecord.sizeBytes=fileStats.size,logRecord.includedTables=tableNames,await this.updateLogRecord(logRecord),this.logger.info("[Backup] Backup completed",{backupId,schemaName:resolvedSchema,tables:backupData.length,rows:totalRows,sizeBytes:fileStats.size}),await this.enforceMaxBackups(),logRecord}catch(err){let msg=err instanceof Error?err.message:String(err);return logRecord.status="failed",logRecord.errorMessage=msg,logRecord.completedAt=new Date().toISOString(),await this.updateLogRecord(logRecord),this.logger.error("[Backup] Backup failed",err,{backupId,schemaName:resolvedSchema}),logRecord}}async restoreFromBackup(backupId,performedBy,targetSchemaName,targetSchemaTables){if(!this.config.allowRestore)return{success:!1,message:"Restore is disabled in configuration"};let resolvedTables=targetSchemaTables||this.schemaTables,logRecord=await this.getLogRecord(backupId);if(!logRecord)return{success:!1,message:"Backup not found"};if(logRecord.status!=="completed")return{success:!1,message:`Cannot restore from backup with status: ${logRecord.status}`};let filePath=join4(this.config.storagePath,logRecord.fileName);try{let raw=await readFile(filePath),content;if(isEncryptedBackup(raw)){if(!this.config.encryptionKey)return{success:!1,message:"Backup is encrypted but no encryption key is configured"};content=decryptBackup(raw,this.config.encryptionKey)}else content=raw.toString("utf-8");let backupFile=JSON.parse(content);await this.createBackup("pre_restore",performedBy,targetSchemaName,targetSchemaTables);let tablesRestored=0,rowsRestored=0,ordered=backupFile.data.map((tableData)=>({tableData,table:resolvedTables[tableData.tableName]})).filter((entry)=>{if(!entry.table)return this.logger.warn(`[Backup] Skipping restore for ${entry.tableData.tableName}: table not found in schema`),!1;return!0});return await this.db.transaction(async(tx)=>{for(let{table}of[...ordered].reverse())await tx.delete(table);for(let{tableData,table}of ordered){if(tableData.rows.length===0)continue;let chunkSize=500;for(let i=0;i<tableData.rows.length;i+=chunkSize){let chunk=reviveRowTypes(table,tableData.rows.slice(i,i+chunkSize));await tx.insert(table).values(chunk)}tablesRestored++,rowsRestored+=tableData.rows.length}}),logRecord.status="restored",await this.updateLogRecord(logRecord),this.logger.info("[Backup] Restore completed",{backupId,tablesRestored,rowsRestored}),{success:!0,message:`Restored ${tablesRestored} tables with ${rowsRestored} rows`,tablesRestored,rowsRestored}}catch(err){let msg=err instanceof Error?err.message:String(err);return this.logger.error("[Backup] Restore failed",err,{backupId}),{success:!1,message:`Restore failed: ${msg}`}}}async listBackups(){if(!this.backupLogsTable)return[];return await this.db.select().from(this.backupLogsTable).orderBy(sql2`created_at DESC`).limit(100)}async getBackupFilePath(backupId){let record=await this.getLogRecord(backupId);if(!record)return null;return join4(this.config.storagePath,record.fileName)}async deleteBackup(backupId){let record=await this.getLogRecord(backupId);if(!record)return!1;let filePath=join4(this.config.storagePath,record.fileName);try{await unlink3(filePath)}catch{}if(this.backupLogsTable)await this.db.delete(this.backupLogsTable).where(eq7(col(this.backupLogsTable,"id"),backupId));return!0}startScheduler(){if(!this.config.schedule.enabled||!this.config.schedule.cron)return;if(!parseCron(this.config.schedule.cron))this.logger.error("[Backup] Cron expression not understood \u2014 falling back to the default",{cron:this.config.schedule.cron,fallback:DEFAULT_CRON,expected:'five fields ("0 2 * * *", "0 3 * * MON", "*/15 * * * *") or a macro (@daily, @weekly, @monthly)'}),this.config={...this.config,schedule:{...this.config.schedule,cron:DEFAULT_CRON}};this.logger.info("[Backup] Scheduler started",{cron:this.config.schedule.cron,timeZone:this.scheduleTimeZone(),retentionDays:this.config.schedule.retentionDays,replicaSafe:Boolean(this.lock)}),this.schedulerActive=!0,this.scheduleNextRun()}scheduleTimeZone(){return this.config.schedule.timeZone||"UTC"}scheduleNextRun(){if(!this.schedulerActive)return;let now=new Date,nextRun=nextCronRun(this.config.schedule.cron,now,this.scheduleTimeZone());if(!nextRun){this.logger.error("[Backup] Cron expression matches no future time \u2014 scheduler stopped",{cron:this.config.schedule.cron}),this.schedulerActive=!1;return}let delayMs=nextRun.getTime()-now.getTime();this.logger.debug?.("[Backup] Next scheduled backup",{at:nextRun.toISOString(),inMs:delayMs});let hop=nextHopMs(delayMs);this.cronTimer=setTimeout(async()=>{if(Date.now()<nextRun.getTime()){this.scheduleNextRun();return}try{if(await this.claimScheduledRun(nextRun))this.logger.info("[Backup] Scheduled backup starting..."),await this.createBackup("scheduled"),await this.cleanupExpiredBackups()}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.error("[Backup] Scheduled backup failed",{error:msg})}finally{this.scheduleNextRun()}},hop)}async claimScheduledRun(fireTime){if(!this.lock)return!0;let key=`nucleus:backup:schedule:${this.schemaName}:${fireTime.toISOString()}`;try{let result=await this.lock.acquireLock(key,3600);if(result.success&&result.data===!1)return this.logger.info("[Backup] Another replica owns this run \u2014 skipping",{fireTime:fireTime.toISOString()}),!1;return!0}catch(err){return this.logger.warn("[Backup] Lock unavailable \u2014 running anyway",{error:err instanceof Error?err.message:String(err)}),!0}}stopScheduler(){if(this.schedulerActive=!1,this.cronTimer)clearTimeout(this.cronTimer),this.cronTimer=null,this.logger.info("[Backup] Scheduler stopped")}getBackupTableNames(tables){return selectBackupTables(tables,this.config.excludeTables)}async insertLogRecord(record){if(!this.backupLogsTable)return;try{await this.db.insert(this.backupLogsTable).values({id:record.id,backupName:record.backupName,fileName:record.fileName,schemaName:record.schemaName,format:record.format,status:record.status,trigger:record.trigger,sizeBytes:record.sizeBytes,tableCount:record.tableCount,rowCount:record.rowCount,includedTables:JSON.stringify(record.includedTables),excludedTables:JSON.stringify(record.excludedTables),errorMessage:record.errorMessage,startedAt:record.startedAt?new Date(record.startedAt):null,completedAt:record.completedAt?new Date(record.completedAt):null,performedBy:record.performedBy,cronExpression:record.cronExpression,retentionDays:record.retentionDays,createdAt:new Date,updatedAt:new Date})}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.warn(`[Backup] Failed to insert backup log: ${msg}`)}}async updateLogRecord(record){if(!this.backupLogsTable)return;try{await this.db.update(this.backupLogsTable).set({status:record.status,sizeBytes:record.sizeBytes,tableCount:record.tableCount,rowCount:record.rowCount,includedTables:JSON.stringify(record.includedTables),errorMessage:record.errorMessage,completedAt:record.completedAt?new Date(record.completedAt):null,updatedAt:new Date}).where(eq7(col(this.backupLogsTable,"id"),record.id))}catch(err){let msg=err instanceof Error?err.message:String(err);this.logger.warn(`[Backup] Failed to update backup log: ${msg}`)}}async getLogRecord(backupId){if(!this.backupLogsTable)return null;return(await this.db.select().from(this.backupLogsTable).where(eq7(col(this.backupLogsTable,"id"),backupId)).limit(1))[0]||null}async enforceMaxBackups(){if(!this.backupLogsTable)return;let allBackups=await this.db.select().from(this.backupLogsTable).where(eq7(col(this.backupLogsTable,"status"),"completed")).orderBy(sql2`created_at DESC`);if(allBackups.length>this.config.maxBackups){let toDelete=allBackups.slice(this.config.maxBackups);for(let backup of toDelete){let b=backup;await this.deleteBackup(b.id)}this.logger.info("[Backup] Old backups cleaned up",{deleted:toDelete.length})}}async cleanupExpiredBackups(){if(!this.backupLogsTable||!this.config.schedule.retentionDays)return;let cutoff=new Date;cutoff.setDate(cutoff.getDate()-this.config.schedule.retentionDays);let{lt}=await import("drizzle-orm"),expired=await this.db.select().from(this.backupLogsTable).where(lt(col(this.backupLogsTable,"createdAt"),cutoff));for(let backup of expired){let b=backup;await this.deleteBackup(b.id)}if(expired.length>0)this.logger.info("[Backup] Expired backups cleaned up",{deleted:expired.length,retentionDays:this.config.schedule.retentionDays})}}var col=(table,name)=>table[name],MAX_TIMEOUT_MS=2147483647,DEFAULT_CRON="0 2 * * *";var init_BackupService=__esm(()=>{init_cron();init_encryption()});var init_Backup=__esm(()=>{init_BackupService()});function parseTimeToSeconds(time){let match=time.match(/^(\d+)(s|m|h|d)$/);if(!match||!match[1]||!match[2])return 300;let value=Number.parseInt(match[1],10);switch(match[2]){case"s":return value;case"m":return value*60;case"h":return value*3600;case"d":return value*86400;default:return 300}}function generateSecureId(){let bytes=new Uint8Array(24);return crypto.getRandomValues(bytes),Array.from(bytes).map((b)=>b.toString(16).padStart(2,"0")).join("")}function hashAnswer(answer){let hasher=new Bun.CryptoHasher("sha256");return hasher.update(answer),hasher.digest("hex")}function timingSafeEqual(a,b){if(a.length!==b.length){let dummy=new Uint8Array(32);return crypto.getRandomValues(dummy),!1}let encoder=new TextEncoder,bufA=encoder.encode(a),bufB=encoder.encode(b),result=0;for(let i=0;i<bufA.length;i++)result|=(bufA[i]??0)^(bufB[i]??0);return result===0}function getSecureRandomInt(min,max){let range=max-min+1,bytesNeeded=Math.ceil(Math.log2(range)/8)||1,maxValue=256**bytesNeeded,limit=maxValue-maxValue%range,randomValue,bytes=new Uint8Array(bytesNeeded);do crypto.getRandomValues(bytes),randomValue=bytes.reduce((acc,byte,i)=>acc+byte*256**i,0);while(randomValue>=limit);return min+randomValue%range}function generateMathChallenge(difficulty){let config=DIFFICULTY_CONFIG[difficulty],{min,max}=config.mathRange,operations=["+","-","\xD7"],operation=operations[getSecureRandomInt(0,operations.length-1)],num1=getSecureRandomInt(min,max),num2=getSecureRandomInt(min,max),answer;switch(operation){case"+":answer=num1+num2;break;case"-":if(num1<num2)[num1,num2]=[num2,num1];answer=num1-num2;break;case"\xD7":num1=getSecureRandomInt(1,12),num2=getSecureRandomInt(1,12),answer=num1*num2;break;default:answer=num1+num2}return{question:`${num1} ${operation} ${num2} = ?`,answer:answer.toString()}}function generateTextChallenge(difficulty){let config=DIFFICULTY_CONFIG[difficulty],text="";for(let i=0;i<config.textLength;i++)text+=CHARACTERS.charAt(getSecureRandomInt(0,CHARACTERS.length-1));return{question:text,answer:text}}function generateImageChallenge(difficulty){let textChallenge=generateTextChallenge(difficulty),width=200,height=60,svgContent=generateCaptchaSVG(textChallenge.answer,200,60),imageData=`data:image/svg+xml;base64,${Buffer.from(svgContent).toString("base64")}`;return{question:"Enter the text shown in the image",answer:textChallenge.answer,imageData}}function getSecureFloat(){let bytes=new Uint32Array(1);return crypto.getRandomValues(bytes),(bytes[0]??0)/4294967295}function generateCaptchaSVG(text,width,height){let bgR=240+getSecureFloat()*15,bgG=240+getSecureFloat()*15,bgB=240+getSecureFloat()*15,bgColor=`rgb(${bgR}, ${bgG}, ${bgB})`,noiseLines="";for(let i=0;i<12;i++){let x1=getSecureFloat()*width,y1=getSecureFloat()*height,x2=getSecureFloat()*width,y2=getSecureFloat()*height,r=getSecureFloat()*100+100,g=getSecureFloat()*100+100,b=getSecureFloat()*100+100,strokeWidth=1+getSecureFloat()*2;noiseLines+=`<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="rgb(${r},${g},${b})" stroke-width="${strokeWidth}"/>`}let noiseCurves="";for(let i=0;i<4;i++){let startX2=getSecureFloat()*width,startY=getSecureFloat()*height,cp1X=getSecureFloat()*width,cp1Y=getSecureFloat()*height,cp2X=getSecureFloat()*width,cp2Y=getSecureFloat()*height,endX=getSecureFloat()*width,endY=getSecureFloat()*height,r=getSecureFloat()*80+80,g=getSecureFloat()*80+80,b=getSecureFloat()*80+80;noiseCurves+=`<path d="M${startX2},${startY} C${cp1X},${cp1Y} ${cp2X},${cp2Y} ${endX},${endY}" stroke="rgb(${r},${g},${b})" stroke-width="2" fill="none"/>`}let noiseDots="";for(let i=0;i<80;i++){let x=getSecureFloat()*width,y=getSecureFloat()*height,r=getSecureFloat()*150+50,g=getSecureFloat()*150+50,b=getSecureFloat()*150+50,radius=getSecureFloat()*3+1;noiseDots+=`<circle cx="${x}" cy="${y}" r="${radius}" fill="rgb(${r},${g},${b})"/>`}let textElements="",charWidth=width/(text.length+2),startX=charWidth;for(let i=0;i<text.length;i++){let x=startX+i*charWidth+(getSecureFloat()-0.5)*15,y=height/2+8+(getSecureFloat()-0.5)*12,rotation=(getSecureFloat()-0.5)*40,fontSize=22+getSecureFloat()*10,r=getSecureFloat()*80,g=getSecureFloat()*80,b=getSecureFloat()*80,skewX=(getSecureFloat()-0.5)*15,scaleY=0.9+getSecureFloat()*0.3;textElements+=`<text x="${x}" y="${y}" font-family="Arial, Helvetica, sans-serif" font-size="${fontSize}" font-weight="bold" fill="rgb(${r},${g},${b})" transform="rotate(${rotation}, ${x}, ${y}) skewX(${skewX}) scale(1, ${scaleY})" style="font-style: ${getSecureFloat()>0.5?"italic":"normal"}">${text[i]}</text>`}let overlayLines="";for(let i=0;i<3;i++){let y=10+getSecureFloat()*(height-20),r=getSecureFloat()*60+60,g=getSecureFloat()*60+60,b=getSecureFloat()*60+60;overlayLines+=`<line x1="0" y1="${y}" x2="${width}" y2="${y+(getSecureFloat()-0.5)*20}" stroke="rgb(${r},${g},${b})" stroke-width="1.5"/>`}return`<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
19
19
|
<defs>
|
|
20
20
|
<filter id="noise" x="0%" y="0%" width="100%" height="100%">
|
|
21
21
|
<feTurbulence type="fractalNoise" baseFrequency="0.04" numOctaves="2" result="noise"/>
|
|
@@ -449,7 +449,7 @@ ${strMDSAlgs}`)}if(attestationStatementAlg!==void 0&&authenticatorGetInfo?.algor
|
|
|
449
449
|
<p>Your account has been created via ${provider} login. You can optionally set a password to also sign in with your email and password.</p>
|
|
450
450
|
<p><a href="${inviteLink}">Set your password</a></p>
|
|
451
451
|
<p>This link expires in 7 days. If you don't want to set a password, you can always sign in with ${provider}.</p>
|
|
452
|
-
`}),logger2.info("[OAUTH] Invite email sent to new OAuth user",{userId,email:profile.email,provider})}catch(emailErr){logger2.warn("[OAUTH] Failed to send invite email",{userId,error:emailErr})}}{let stateUser=(await db.select().from(usersTable).where(eq57(usersTable.id,userId)).limit(1))[0],state2=stateUser?evaluateAccountState(stateUser):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!state2.allowed)return logger2.warn(`[OAUTH] Login blocked - account ${state2.reason}`,{userId,provider}),ctx.set.status=302,ctx.set.headers.Location=`${errorRedirect}?error=account_${state2.reason}`,null}let defaultRoleNames=resolveDefaultRoleNames(config.authentication);if(defaultRoleNames.length>0){let resolvedForRole=resolveAuthTablesForRequest(ctx.request,config);await assignDefaultRoles({db,userId,roleNames:defaultRoleNames,rolesTable:resolvedForRole.rolesTable??config.rolesTable??null,userRolesTable:resolvedForRole.userRolesTable??config.userRolesTable??null,logger:logger2})}let syncConfig=oauthService.profileSync;if(syncConfig){let syncTables=resolveAuthTablesForRequest(ctx.request,config);await applyProfileSync({db,usersTable,profilesTable:syncTables.schemaTables?.profiles,userId,rawProfile:profile.rawProfile,config:syncConfig,isNewUser:createdNewUser,logger:logger2})}await db.update(usersTable).set({lastLoginAt:new Date}).where(eq57(usersTable.id,userId));let ipAddress=ctx.request.headers.get("cf-connecting-ip")?.trim()||ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"127.0.0.1",userAgent=ctx.request.headers.get("user-agent")||"Unknown Browser",deviceInfo=parseUserAgentForLogin(userAgent,ipAddress,void 0,deviceContextFromRequest(ctx.request).clientHints),oauthUserRoles=[],oauthUserClaims=[],oauthUserClaimScopes={};if(config.db)try{let resolved2=resolveAuthTablesForRequest(ctx.request,config),rc=await fetchUserRolesAndClaims(config.db,userId,resolved2);oauthUserRoles=rc.roles,oauthUserClaims=rc.claims,oauthUserClaimScopes=rc.claimScopes}catch{}let requestOrigin=ctx.request.headers.get("origin")||ctx.request.headers.get("referer")?.replace(/\/[^/]*$/,"")||void 0,sessionParams={userId,deviceInfo,loginMethod:`oauth:${provider}`,rememberMe:!0,requestOrigin},sessionId=await createSession(sessionParams),accessToken=signAccessToken(userId,oauthUserRoles.length>0?oauthUserRoles:void 0,oauthUserClaims.length>0?oauthUserClaims:void 0,ctx.request.headers.get("x-tenant-schema")??void 0,oauthUserClaimScopes,sessionId),refreshToken=signRefreshToken(userId,void 0,sessionId),requiresApproval=!1,approvalSessionId=sessionId,deviceTokenCookie;if(saveSessionToDb){let oauthSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,dtCfg=config.authentication?.deviceTrust;if(dtCfg?.enabled)sessionParams.deviceToken=readDeviceTokenFromCookieHeader(ctx.request.headers.get("cookie"),dtCfg);let saveResult=await saveSessionToDb(sessionId,sessionParams,oauthSchemaName);if(saveResult?.denied)return logger2.warn("[OAUTH] Login blocked by device-trust",{userId,provider}),ctx.set.status=302,ctx.set.headers.Location=`${errorRedirect}?error=device_not_recognized`,null;if(deviceTokenCookie=saveResult?.deviceTokenCookie,saveResult?.requiresApproval){if(requiresApproval=!0,saveResult.sessionId)approvalSessionId=saveResult.sessionId}}if(requiresApproval){if(deviceTokenCookie)ctx.set.headers["Set-Cookie"]=deviceTokenCookie;logger2.info("[OAUTH] Login requires device approval",{userId,provider,approvalSessionId});let pendingUrl=absolutizeRedirect(resolveSafeOAuthRedirect(statePayload.redirectUrl,oauthService.successRedirectUrl,config.authentication?.trustedAppOrigins),portalOrigin);return ctx.set.status=302,ctx.set.headers.Location=`${pendingUrl}?requires_approval=true&provider=${provider}&session_id=${approvalSessionId}`,null}await logger2.audit({entityName:"users",entityId:userId,operation:"LOGIN",userId,summary:`${profile.email??profile.providerAccountId} logged in via OAuth (${provider})`,ipAddress,userAgent,path:`${basePath}/${provider}/callback`,query:""});let securePart=cookies.secure?"; Secure":"",domainPart=cookies.domain?`; Domain=${cookies.domain}`:"",cookieOptions=`; Path=${cookies.path}; HttpOnly; SameSite=${cookies.sameSite}${securePart}${domainPart}`,cookiesToSet=[];if(tokenConfig.accessToken.setHeadersEnabled)cookiesToSet.push(`${cookies.accessTokenName}=${accessToken}${cookieOptions}; Max-Age=${cookies.accessTokenMaxAge}`);if(tokenConfig.refreshToken.setHeadersEnabled)cookiesToSet.push(`${cookies.refreshTokenName}=${refreshToken}${cookieOptions}; Max-Age=${cookies.refreshTokenMaxAge}`);if(tokenConfig.sessionToken.setHeadersEnabled)cookiesToSet.push(`${cookies.sessionTokenName}=${sessionId}${cookieOptions}; Max-Age=${cookies.sessionTokenMaxAge}`);if(deviceTokenCookie)cookiesToSet.push(deviceTokenCookie);let successUrl=absolutizeRedirect(resolveSafeOAuthRedirect(statePayload.redirectUrl,oauthService.successRedirectUrl,config.authentication?.trustedAppOrigins),portalOrigin),headers=new Headers;headers.set("Location",successUrl);for(let cookie of cookiesToSet)headers.append("Set-Cookie",cookie);return new Response(null,{status:302,headers})}}),routeGetProviders=defineRoute({method:"GET",path:"/providers",detail:{tags:["Authentication"],summary:"List OAuth Providers",description:"Returns the list of enabled OAuth providers"},handler:()=>{return{success:!0,data:{providers:oauthService.getEnabledProviders()}}}}),routeGetLinkProvider=defineRoute({method:"GET",path:"/link/:provider",detail:{tags:["Authentication"],summary:"Link OAuth Account",description:"Redirects to provider to link an OAuth account to the current user"},handler:async(ctx)=>{let provider=ctx.params.provider;if(!oauthService.isProviderEnabled(provider))return ctx.set.status=404,{success:!1,message:`OAuth provider "${provider}" is not enabled`};if(!oauthService.allowAccountLinking)return ctx.set.status=403,{success:!1,message:"Account linking is disabled"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required to link accounts"};let redirectUrl=ctx.query.redirect_url,authUrl=await oauthService.buildAuthorizationUrl(provider,userId,redirectUrl),issuedState=new URL(authUrl).searchParams.get("state");if(issuedState)ctx.set.headers["Set-Cookie"]=buildOAuthStateCookie(issuedState,{maxAge:600,secure:cookies.secure,domain:cookies.domain});return ctx.set.status=302,ctx.set.headers.Location=authUrl,null}}),routeDeleteUnlinkProvider=defineRoute({method:"DELETE",path:"/unlink/:provider",detail:{tags:["Authentication"],summary:"Unlink OAuth Account",description:"Removes a linked OAuth account from the current user"},handler:async(ctx)=>{let provider=ctx.params.provider,userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let oauthTable=config.oauthAccountsTable;if(!oauthTable)return ctx.set.status=500,{success:!1,message:"OAuth accounts table not configured"};if((await db.select().from(oauthTable).where(and25(eq57(oauthTable.userId,userId),eq57(oauthTable.provider,provider))).limit(1)).length===0)return ctx.set.status=404,{success:!1,message:`No linked ${provider} account found`};let{usersTable:resolvedUsersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!resolvedUsersTable)return ctx.set.status=500,{success:!1,message:"Users table not configured"};let hasPassword=!!(await db.select().from(resolvedUsersTable).where(eq57(resolvedUsersTable.id,userId)).limit(1))[0]?.password,allOAuthAccounts=await db.select().from(oauthTable).where(eq57(oauthTable.userId,userId));if(!hasPassword&&allOAuthAccounts.length<=1)return ctx.set.status=400,{success:!1,message:"Cannot unlink the only login method. Set a password first."};return await db.delete(oauthTable).where(and25(eq57(oauthTable.userId,userId),eq57(oauthTable.provider,provider))),logger2.info("[OAUTH] Account unlinked",{userId,provider}),{success:!0,message:`${provider} account unlinked successfully`}}}),routeGetAccounts=defineRoute({method:"GET",path:"/accounts",detail:{tags:["Authentication"],summary:"List Linked OAuth Accounts",description:"Returns all OAuth accounts linked to the current user"},handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let oauthTable=config.oauthAccountsTable;if(!oauthTable)return{success:!0,data:{accounts:[]}};return{success:!0,data:{accounts:(await db.select().from(oauthTable).where(eq57(oauthTable.userId,userId))).map((a)=>({id:a.id,provider:a.provider,providerEmail:a.providerEmail,providerName:a.providerName,providerAvatarUrl:a.providerAvatarUrl,isPrimary:a.isPrimary,lastUsedAt:a.lastUsedAt,createdAt:a.createdAt}))}}}});return collectRoutes([{prefix:basePath,routes:[routeGetProvider,routeGetProviderCallback,routeGetProviders,routeGetLinkProvider,routeDeleteUnlinkProvider,routeGetAccounts]}])}var OAUTH_STATE_COOKIE="oauth_state",readCookie=(request,name2)=>{let raw=request.headers.get("cookie");if(!raw)return;for(let part of raw.split(";")){let trimmed=part.trim(),eq58=trimmed.indexOf("=");if(eq58>0&&trimmed.slice(0,eq58)===name2)return trimmed.slice(eq58+1)}return},resolveSafeOAuthRedirect=(candidate,fallback,allowedOrigins)=>{if(!candidate)return fallback;let normalized=candidate.replace(/[\t\n\r]/g,"");if(!normalized)return fallback;if(normalized.startsWith("/")&&normalized[1]!=="/"&&normalized[1]!=="\\")return normalized;try{let candHost=new URL(normalized).host.toLowerCase(),trusted=[];try{trusted.push(new URL(fallback).host.toLowerCase())}catch{}for(let o of allowedOrigins??[])try{trusted.push(new URL(o.includes("://")?o:`https://${o}`).host.toLowerCase())}catch{}for(let t of trusted)if(t.startsWith("*.")){let base=t.slice(2);if(candHost===base||candHost.endsWith(`.${base}`))return normalized}else if(candHost===t)return normalized}catch{}return fallback},absolutizeRedirect=(target2,portalOrigin)=>portalOrigin&&target2.startsWith("/")&&target2[1]!=="/"?`${portalOrigin}${target2}`:target2;var init_oauth=__esm(()=>{init_DeviceTrust();init_routeCollector();init_assignDefaultRole();init_fetchUserRolesAndClaims();init_deviceInfo();init_utils7();init_utils8();init_applyProfileSync()});var PasswordChangeBodySchema,PasswordChangeResponseSchema;var init_types15=__esm(()=>{init_esm3();PasswordChangeBodySchema=Type.Object({currentPassword:Type.Optional(Type.String()),newPassword:Type.String({minLength:8}),confirmPassword:Type.String({minLength:8})}),PasswordChangeResponseSchema=Type.Object({success:Type.Boolean(),message:Type.Optional(Type.String())})});function validatePasswordsMatch(newPassword,confirmPassword){return newPassword===confirmPassword}var exports_store={};__export(exports_store,{userHasNoTrustedDevices:()=>userHasNoTrustedDevices,touchDevice:()=>touchDevice,revokeUserDevices:()=>revokeUserDevices,revokeDevicesBySessionIds:()=>revokeDevicesBySessionIds,revokeDeviceById:()=>revokeDeviceById,rejectDeviceForSession:()=>rejectDeviceForSession,listUserDevices:()=>listUserDevices,insertDeviceRow:()=>insertDeviceRow,findDeviceRowsByRawToken:()=>findDeviceRowsByRawToken,activateDeviceForSession:()=>activateDeviceForSession});import{and as and26,eq as eq58,inArray as inArray19}from"drizzle-orm";async function findDeviceRowsByRawToken(db,table,rawToken){let hash=hashDeviceToken(rawToken);return await db.select().from(table).where(eq58(col14(table,"tokenHash"),hash)).limit(2)}async function insertDeviceRow(db,table,v){let now=new Date;await db.insert(table).values({id:v.id,userId:v.userId,tokenHash:v.tokenHash,status:v.status,originSessionId:v.originSessionId??null,label:v.label??null,deviceFingerprint:v.deviceFingerprint??null,firstSeenIp:v.firstSeenIp??null,lastSeenIp:v.lastSeenIp??v.firstSeenIp??null,lastSeenAt:now,expiresAt:v.expiresAt,isActive:!0,createdAt:now,updatedAt:now})}async function activateDeviceForSession(db,table,sessionId){return(await db.update(table).set({status:"trusted",updatedAt:new Date}).where(and26(eq58(col14(table,"originSessionId"),sessionId),eq58(col14(table,"status"),"pending"))).returning({id:col14(table,"id")})).length}async function rejectDeviceForSession(db,table,sessionId){await db.update(table).set({status:"revoked",revokedAt:new Date,revokedReason:"replaced",isActive:!1,updatedAt:new Date}).where(and26(eq58(col14(table,"originSessionId"),sessionId),eq58(col14(table,"status"),"pending")))}async function touchDevice(db,table,id,ip){await db.update(table).set({lastSeenAt:new Date,lastSeenIp:ip??null,updatedAt:new Date}).where(eq58(col14(table,"id"),id))}async function revokeWhere(db,table,where,reason){await db.update(table).set({status:"revoked",revokedAt:new Date,revokedReason:reason,isActive:!1,updatedAt:new Date}).where(where)}async function revokeUserDevices(db,table,userId,reason){if(!userId)return;let notAlready=and26(eq58(col14(table,"userId"),userId),eq58(col14(table,"status"),"trusted")),alsoPending=and26(eq58(col14(table,"userId"),userId),eq58(col14(table,"status"),"pending"));await revokeWhere(db,table,notAlready,reason),await revokeWhere(db,table,alsoPending,reason)}async function revokeDevicesBySessionIds(db,table,sessionIds,reason){if(!sessionIds?.length)return;await revokeWhere(db,table,inArray19(col14(table,"originSessionId"),sessionIds),reason)}async function revokeDeviceById(db,table,id,userId,reason){return(await db.update(table).set({status:"revoked",revokedAt:new Date,revokedReason:reason,isActive:!1,updatedAt:new Date}).where(and26(eq58(col14(table,"id"),id),eq58(col14(table,"userId"),userId))).returning({id:col14(table,"id")})).length}async function listUserDevices(db,table,userId){return(await db.select().from(table).where(eq58(col14(table,"userId"),userId))).map((r)=>{let{tokenHash:_omit,...safe}=r;return safe})}async function userHasNoTrustedDevices(db,table,userId){return(await db.select({id:col14(table,"id")}).from(table).where(and26(eq58(col14(table,"userId"),userId),eq58(col14(table,"status"),"trusted"))).limit(1)).length===0}var col14=(t,name2)=>t[name2];var init_store3=__esm(()=>{init_DeviceTrust()});import{eq as eq59}from"drizzle-orm";function createPasswordChangeRoute(config,passwordChangeConfig){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_PASSWORD_CHANGE),route=passwordChangeConfig.route||"/auth/password-change";if(!passwordChangeConfig.enabled)return collectRoutes();let routePostRoute=defineRoute({method:"POST",path:"/",body:PasswordChangeBodySchema,detail:{tags:["Authentication"],summary:"Change Password",description:"Change password for authenticated user"},handler:async(ctx)=>{let{usersTable,sessionsTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{currentPassword,newPassword,confirmPassword}=ctx.body;if(!validatePasswordsMatch(newPassword,confirmPassword))return ctx.set.status=422,{success:!1,message:"New passwords do not match"};let strength=validatePasswordStrength(newPassword,config.authentication?.passwordPolicy);if(!strength.valid)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:strength.errors};let user=(await db.select().from(usersTable).where(eq59(usersTable.id,userId)).limit(1))[0];if(!user)return ctx.set.status=404,{success:!1,message:"User not found"};let identityError=identityRuleError(newPassword,config.authentication?.passwordPolicy,typeof user.email==="string"?user.email:void 0);if(identityError)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:[identityError]};let existingHash=user.password??"",userHasPassword=existingHash.length>0,isInitialSet=!userHasPassword,reqUrl=new URL(ctx.request.url),auditIp=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",auditUa=ctx.request.headers.get("user-agent")||"unknown";if(userHasPassword){if(!currentPassword)return ctx.set.status=400,{success:!1,message:"Current password is required"};if(!await verifyPassword(currentPassword,existingHash))return log4.warn("Password change failed - invalid current password",{userId}),logger2.audit({entityName:"users",entityId:userId,operation:"PASSWORD_CHANGE_FAILED",userId,summary:"Password change failed: invalid current password",ipAddress:auditIp,userAgent:auditUa,path:reqUrl.pathname,query:reqUrl.search}),ctx.set.status=400,{success:!1,message:"Current password is incorrect"}}let hashedNewPassword=await hashPassword(newPassword);if(await db.update(usersTable).set({password:hashedNewPassword,updatedAt:new Date}).where(eq59(usersTable.id,userId)),!isInitialSet&&sessionsTable)try{await db.update(sessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"password_change"}).where(eq59(sessionsTable.userId,userId))}catch(err){log4.warn("Failed to revoke sessions after password change",{userId,error:err instanceof Error?err.message:String(err)})}if(!isInitialSet&&config.authentication?.deviceTrust?.enabled)try{let{schemaTables}=resolveAuthTablesForRequest(ctx.request,config),dtTable=schemaTables?.trustedDevices??schemaTables?.trusted_devices;if(dtTable&&db){let{revokeUserDevices:revokeUserDevices2}=await Promise.resolve().then(() => (init_store3(),exports_store));await revokeUserDevices2(db,dtTable,userId,"password_reset")}}catch(err){log4.warn("Failed to revoke device tokens after password change",{userId,error:err instanceof Error?err.message:String(err)})}return log4.info(isInitialSet?"Initial password set successful":"Password change successful",{userId}),logger2.audit({entityName:"users",entityId:userId,operation:isInitialSet?"PASSWORD_SET":"PASSWORD_CHANGE",userId,summary:isInitialSet?"Initial password set successfully":"Password changed successfully",ipAddress:auditIp,userAgent:auditUa,path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:isInitialSet?"Password set successfully":"Password changed successfully"}}});return collectRoutes([{prefix:route,routes:[routePostRoute]}])}var init_passwordChange=__esm(()=>{init_scopes();init_routeCollector();init_utils7();init_passwordPolicy();init_utils6();init_types15();init_types15()});function describeResetEmail(outcome){if(!outcome||outcome.sent)return{sent:!0,level:"info",message:"Password reset email sent"};let base=SENTENCES[outcome.reason],detail=outcome.detail?.trim();return{sent:!1,level:outcome.reason==="exempt"?"info":"warn",message:detail?`${base} (${detail})`:base}}var SENTENCES;var init_outcome=__esm(()=>{SENTENCES={no_provider:"Password reset email NOT sent \u2014 no email provider is configured. The token was stored, so a link exists, but nothing carried it.",exempt:"Password reset email not sent \u2014 the address is on an exempt domain this install never mails.",rejected:"Password reset email NOT sent \u2014 the provider refused the recipient. The address is accepted at login but not deliverable.",error:"Password reset email NOT sent \u2014 the send failed."}});var PasswordResetRequestSchema,PasswordResetConfirmSchema,PasswordResetResponseSchema;var init_types16=__esm(()=>{init_esm3();PasswordResetRequestSchema=Type.Object({email:Type.String({format:"email"})}),PasswordResetConfirmSchema=Type.Object({token:Type.String(),newPassword:Type.String({minLength:8}),confirmPassword:Type.String({minLength:8})}),PasswordResetResponseSchema=Type.Object({success:Type.Boolean(),message:Type.Optional(Type.String())})});import{randomBytes as randomBytes7}from"crypto";function generateResetToken(){return randomBytes7(32).toString("hex")}function isTokenExpired(expiresAt){return new Date>expiresAt}var init_utils10=()=>{};function createPasswordResetRoute(config,passwordResetConfig,storeResetToken,getResetToken,deleteResetToken,sendResetEmail){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_PASSWORD_RESET),baseRoute=passwordResetConfig.route||"/auth/password-reset";if(!passwordResetConfig.enabled)return collectRoutes();let routePostBaserouteRequest=defineRoute({method:"POST",path:"/request",body:PasswordResetRequestSchema,detail:{tags:["Authentication"],summary:"Request Password Reset",description:"Request a password reset email"},handler:async(ctx)=>{let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{email:rawEmail}=ctx.body,email=rawEmail.toLowerCase(),{eq:eq60}=await import("drizzle-orm"),user=(await db.select().from(usersTable).where(eq60(usersTable.email,email)).limit(1))[0];if(!user)return{success:!0,message:"If email exists, reset link will be sent"};let token=generateResetToken(),expiresAt=new Date(Date.now()+3600000),reqSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0;await storeResetToken(user.id,token,expiresAt,reqSchemaName);let delivery={sent:!1,level:"warn",message:"Password reset email NOT sent \u2014 no send helper is configured."};if(sendResetEmail)try{delivery=describeResetEmail(await sendResetEmail(email,token,ctx.request))}catch(error3){delivery=describeResetEmail({sent:!1,reason:"error",detail:error3 instanceof Error?error3.message:String(error3)})}if(delivery.level==="warn")log4.warn(delivery.message,{email});else log4.info(delivery.message,{email});log4.info("Password reset requested",{userId:user.id,email});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"users",entityId:user.id,operation:"PASSWORD_RESET_REQUEST",userId:user.id,summary:`Password reset requested for ${email} \u2014 ${delivery.sent?"email sent":"EMAIL NOT SENT"}`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:"If email exists, reset link will be sent"}}}),routePostBaserouteConfirm=defineRoute({method:"POST",path:"/confirm",body:PasswordResetConfirmSchema,detail:{tags:["Authentication"],summary:"Confirm Password Reset",description:"Reset password with token"},handler:async(ctx)=>{let{usersTable,sessionsTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{token,newPassword,confirmPassword}=ctx.body;if(newPassword!==confirmPassword)return ctx.set.status=400,{success:!1,message:"Passwords do not match"};let strength=validatePasswordStrength(newPassword,config.authentication?.passwordPolicy);if(!strength.valid)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:strength.errors};let reqSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,resetData=await getResetToken(token,reqSchemaName);if(!resetData)return ctx.set.status=400,{success:!1,message:"Invalid or expired reset token"};if(isTokenExpired(resetData.expiresAt))return await deleteResetToken(token,reqSchemaName),ctx.set.status=400,{success:!1,message:"Reset token has expired"};let{eq:eq60}=await import("drizzle-orm");if(config.authentication?.passwordPolicy?.preventUserInfoInPassword){let ownerEmail=(await db.select().from(usersTable).where(eq60(usersTable.id,resetData.userId)).limit(1))[0]?.email,identityError=identityRuleError(newPassword,config.authentication?.passwordPolicy,typeof ownerEmail==="string"?ownerEmail:void 0);if(identityError)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:[identityError]}}let hashedPassword=await hashPassword(newPassword);if(await db.update(usersTable).set({password:hashedPassword}).where(eq60(usersTable.id,resetData.userId)),await deleteResetToken(token,reqSchemaName),sessionsTable)try{await db.update(sessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"password_reset"}).where(eq60(sessionsTable.userId,resetData.userId))}catch(err){log4.warn("Failed to revoke sessions after password reset",{userId:resetData.userId,error:err instanceof Error?err.message:String(err)})}try{if(config.authentication?.deviceTrust?.enabled){let{schemaTables}=resolveAuthTablesForRequest(ctx.request,config),dtTable=schemaTables?.trustedDevices??schemaTables?.trusted_devices;if(dtTable&&db){let{revokeUserDevices:revokeUserDevices2}=await Promise.resolve().then(() => (init_store3(),exports_store));await revokeUserDevices2(db,dtTable,resetData.userId,"password_reset")}}}catch(err){log4.warn("Failed to revoke device tokens after password reset",{userId:resetData.userId,error:err instanceof Error?err.message:String(err)})}log4.info("Password reset successful",{userId:resetData.userId});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"users",entityId:resetData.userId,operation:"PASSWORD_RESET",userId:resetData.userId,summary:"Password reset completed successfully",ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:"Password has been reset"}}});return collectRoutes([{prefix:baseRoute,routes:[routePostBaserouteRequest,routePostBaserouteConfirm]}])}var init_passwordReset=__esm(()=>{init_scopes();init_routeCollector();init_passwordPolicy();init_utils6();init_outcome();init_types16();init_utils10();init_types16()});var PasswordSetBodySchema,PasswordSetResponseSchema;var init_types17=__esm(()=>{init_esm3();PasswordSetBodySchema=Type.Object({newPassword:Type.String({minLength:8}),userId:Type.Optional(Type.String()),token:Type.Optional(Type.String())}),PasswordSetResponseSchema=Type.Object({success:Type.Boolean(),message:Type.String()})});import{eq as eq60}from"drizzle-orm";function createPasswordSetRoute(config,passwordSetConfig,getMagicToken,deleteMagicToken){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_PASSWORD_SET),route=passwordSetConfig.route||"/auth/password-set";if(!passwordSetConfig.enabled)return collectRoutes();let routePostRoute=defineRoute({method:"POST",path:"/",body:PasswordSetBodySchema,detail:{tags:["Authentication"],summary:"Set Password",description:"Set password for the first time (for invited users who do not have a password yet)"},handler:async(ctx)=>{log4.info("Password set request received");let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return log4.error("Password set failed - database not configured"),ctx.set.status=500,{success:!1,message:"Database not configured"};let{newPassword,token}=ctx.body,strength=validatePasswordStrength(newPassword,config.authentication?.passwordPolicy);if(!strength.valid)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:strength.errors};let userId=null;if(token&&getMagicToken&&deleteMagicToken){let reqSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,tokenHash=hashToken(token,TOKEN_PURPOSE.invite),storedToken=await getMagicToken(tokenHash,reqSchemaName);if(!storedToken)return log4.warn("Password set failed - invalid token"),ctx.set.status=400,{success:!1,message:"Invalid or expired token"};if(new Date>storedToken.expiresAt)return await deleteMagicToken(tokenHash,reqSchemaName),log4.warn("Password set failed - expired token",{email:storedToken.email}),ctx.set.status=400,{success:!1,message:"Invalid or expired token"};userId=storedToken.userId,log4.info("Password set - userId resolved from token",{userId,email:storedToken.email})}else userId=ctx.request.headers.get("x-user-id");if(!userId)return log4.warn("Password set failed - no token and no authenticated user"),ctx.set.status=401,{success:!1,message:"Valid token or authentication required"};let user=(await db.select().from(usersTable).where(eq60(usersTable.id,userId)).limit(1))[0];if(log4.info("Password set - user found",{found:!!user,hasPassword:!!user?.password}),!user)return ctx.set.status=404,{success:!1,message:"User not found"};let identityError=identityRuleError(newPassword,config.authentication?.passwordPolicy,typeof user.email==="string"?user.email:void 0);if(identityError)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:[identityError]};if(user.password)return log4.warn("Password set failed - user already has password",{userId}),ctx.set.status=409,{success:!1,message:"Password already set. Use password change instead."};let hashedPassword=await hashPassword(newPassword);log4.info("Password set - updating user with verifiedAt",{userId});let updateResult=await db.update(usersTable).set({password:hashedPassword,verifiedAt:new Date,updatedAt:new Date}).where(eq60(usersTable.id,userId));if(log4.info("Password set successful for invited user",{userId,updateResult}),token&&deleteMagicToken){let setSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,tokenHash=hashToken(token,TOKEN_PURPOSE.invite);await deleteMagicToken(tokenHash,setSchemaName),log4.info("Invite token consumed after password set",{userId})}return{success:!0,message:"Password set successfully"}}});return collectRoutes([{prefix:route,routes:[routePostRoute]}])}var init_passwordSet=__esm(()=>{init_scopes();init_routeCollector();init_utils8();init_passwordPolicy();init_utils6();init_types17();init_types17()});function parseTimeToSeconds3(time2){let match=time2.match(/^(\d+)([smhd])$/);if(!match)return 900;let value2=match[1],unit=match[2];if(!value2||!unit)return 900;let num3=parseInt(value2,10);switch(unit){case"s":return num3;case"m":return num3*60;case"h":return num3*3600;case"d":return num3*86400;default:return 900}}var RefreshResponseSchema;var init_types18=__esm(()=>{init_esm3();RefreshResponseSchema=Type.Object({success:Type.Boolean(),message:Type.Optional(Type.String()),data:Type.Optional(Type.Object({accessToken:Type.String()}))})});import{eq as eq61}from"drizzle-orm";function createRefreshRoute(config,refreshConfig,verifyRefreshToken,signAccessToken,signRefreshToken,tokenResponseConfig,cookieMaxAgeBufferSeconds,cookieConfig){let{logger:logger2,authentication}=config,route=refreshConfig.route||"/auth/refresh";if(!refreshConfig.enabled)return collectRoutes();let routePostRoute=defineRoute({method:"POST",path:"/",detail:{tags:["Authentication"],summary:"Refresh Token",description:"Get a new access token using a refresh token. Browsers send it as the refresh cookie; a header-only client sends it as `Authorization: Bearer <refresh token>`."},handler:async(ctx)=>{let refreshTokenName=authentication?.refreshToken?.name||"refresh_token",accessTokenName=authentication?.accessToken?.name||"access_token",refreshToken=null,cookieHeader=ctx.request.headers.get("cookie");if(cookieHeader)refreshToken=cookieHeader.split(";").reduce((acc,cookie)=>{let trimmed=cookie.trim(),eqIndex=trimmed.indexOf("=");if(eqIndex>0)acc[trimmed.slice(0,eqIndex)]=trimmed.slice(eqIndex+1);return acc},{})[refreshTokenName]||null;if(!refreshToken){let authorization=ctx.request.headers.get("authorization")??"";refreshToken=/^Bearer\s+(.+)$/i.exec(authorization.trim())?.[1]?.trim()||null}if(!refreshToken)return logger2.debug("[AUTH] Refresh skipped - no refresh cookie or bearer token on the request"),ctx.set.status=401,{success:!1,message:"Refresh token required"};let result=verifyRefreshToken(refreshToken);if(!result.valid||!result.payload)return logger2.warn("[AUTH] Refresh failed - invalid token"),ctx.set.status=401,{success:!1,message:"Invalid refresh token"};let userId=result.payload.sub,resolved=resolveAuthTablesForRequest(ctx.request,config),statelessMode=authentication?.mode==="consumer",boundSessionId=typeof result.payload.sessionId==="string"?result.payload.sessionId:"",sessionRememberMe,supersededHash;if(!statelessMode){if(!boundSessionId)return logger2.warn("[AUTH] Refresh blocked - token carries no session",{userId}),ctx.set.status=401,{success:!1,message:"Refresh token is not bound to a session"};let session=await refreshSessionIsAlive({sessionId:boundSessionId,db:config.db,sessionsTable:resolved.sessionsTable});if(!session.alive)return logger2.warn("[AUTH] Refresh blocked - session is no longer active",{userId,sessionId:boundSessionId,reason:session.reason}),ctx.set.status=401,{success:!1,message:"Session is no longer active"};sessionRememberMe=session.rememberMe;let verdict=classifyRefreshToken({presentedHash:hashRefreshToken(refreshToken),currentHash:session.refreshTokenHash,previousHash:session.previousRefreshTokenHash,previousRotatedAt:session.previousRefreshTokenAt,nowMs:Date.now()});if(verdict.action==="revoke")return logger2.warn("[AUTH] Refresh token reuse detected - ending the session",{userId,sessionId:boundSessionId,reason:verdict.reason}),await deleteSession({sessionId:boundSessionId}).catch(()=>{return}),ctx.set.status=401,{success:!1,message:"Session is no longer active"};supersededHash=session.refreshTokenHash}let userRoles=[],userClaims=[],userClaimScopes={};if(config.db){try{let rc=await fetchUserRolesAndClaims(config.db,userId,resolved);userRoles=rc.roles,userClaims=rc.claims,userClaimScopes=rc.claimScopes}catch(roleError){logger2.error("[AUTH] Failed to fetch roles/claims during refresh",{userId,error:roleError instanceof Error?roleError.message:String(roleError)})}try{let usersTable=resolved.usersTable;if(usersTable){let user=(await config.db.select().from(usersTable).where(eq61(usersTable.id,userId)).limit(1))[0];if(!user||user.isActive===!1)return logger2.warn("[AUTH] Refresh blocked - account inactive",{userId}),ctx.set.status=401,{success:!1,message:"Account is not active"};let lockedUntilRaw=user.lockedUntil,lockedUntil=lockedUntilRaw?new Date(lockedUntilRaw):null;if(user.isLocked===!0&&(!lockedUntil||lockedUntil>new Date))return logger2.warn("[AUTH] Refresh blocked - account locked",{userId}),ctx.set.status=401,{success:!1,message:"Account is locked"};let userCohortId=user.cohortId;if(userCohortId){let cohortsTable=resolved.schemaTables?.userCohorts??resolved.schemaTables?.user_cohorts;if(cohortsTable){let cohortExpiresAt=(await config.db.select().from(cohortsTable).where(eq61(cohortsTable.id,userCohortId)).limit(1))[0]?.expiresAt;if(cohortExpiresAt&&new Date(cohortExpiresAt)<new Date)return logger2.warn("[AUTH] Refresh blocked - cohort expired",{userId,cohortId:userCohortId}),ctx.set.status=401,{success:!1,message:"Your access has expired. Please contact your administrator."}}}}}catch(cohortErr){logger2.error("[AUTH] Failed cohort expiry check during refresh",{userId,error:cohortErr instanceof Error?cohortErr.message:String(cohortErr)})}}let newAccessToken=signAccessToken(userId,userRoles.length>0?userRoles:void 0,userClaims.length>0?userClaims:void 0,ctx.request.headers.get("x-tenant-schema")??void 0,userClaimScopes,boundSessionId||void 0),newRefreshToken=signRefreshToken?signRefreshToken(userId,sessionRememberMe,boundSessionId||void 0):null;await recordIssuedRefreshToken(boundSessionId||void 0,newRefreshToken,{previousHash:supersededHash});let accessSetHeaders=tokenResponseConfig?.accessToken?.setHeadersEnabled??!0,accessReturnJson=tokenResponseConfig?.accessToken?.returnJson??!0,refreshSetHeaders=tokenResponseConfig?.refreshToken?.setHeadersEnabled??!0,refreshReturnJson=tokenResponseConfig?.refreshToken?.returnJson??!1,accessExpiresIn=authentication?.accessToken?.expiresIn||"15m",accessMaxAge=Math.max(0,parseTimeToSeconds3(accessExpiresIn)-(cookieMaxAgeBufferSeconds??0)),refreshTtl=longerLifetime(sessionRememberMe?authentication?.rememberMe?.expiresIn:void 0,authentication?.refreshToken?.expiresIn,604800),refreshMaxAge=cookieMaxAge(refreshTtl),headers=new Headers;headers.set("Content-Type","application/json");let cookiePath=cookieConfig?.path||"/",cookieSameSite=cookieConfig?.sameSite||"Strict",securePart=cookieConfig?.secure!==!1?"; Secure":"",domainPart=cookieConfig?.domain?`; Domain=${cookieConfig.domain}`:"",cookieOpts=`; Path=${cookiePath}; HttpOnly; SameSite=${cookieSameSite}${securePart}${domainPart}`;if(accessSetHeaders)headers.append("Set-Cookie",`${accessTokenName}=${newAccessToken}${cookieOpts}; Max-Age=${accessMaxAge}`);if(newRefreshToken&&refreshSetHeaders)headers.append("Set-Cookie",`${refreshTokenName}=${newRefreshToken}${cookieOpts}; Max-Age=${refreshMaxAge}`);logger2.info("[AUTH] Token refresh successful",{userId,rotatedRefreshToken:!!newRefreshToken});let responseData={};if(accessReturnJson)responseData.accessToken=newAccessToken;if(newRefreshToken&&refreshReturnJson)responseData.refreshToken=newRefreshToken;let jsonBody=JSON.stringify(withEnvelopeFlags({success:!0,data:responseData}));return new Response(jsonBody,{status:200,headers})}});return collectRoutes([{prefix:route,routes:[routePostRoute]}])}var init_refresh=__esm(()=>{init_Delete2();init_response();init_routeCollector();init_lifetime();init_fetchUserRolesAndClaims();init_recordIssued();init_reuseDetection();init_sessionBinding();init_types18()});var RegisterBodySchema,RegisterResponseSchema;var init_types19=__esm(()=>{init_esm3();RegisterBodySchema=Type.Object({email:Type.String({format:"email"}),password:Type.String({minLength:8}),confirmPassword:Type.Optional(Type.String({minLength:8})),firstName:Type.Optional(Type.String({maxLength:100})),lastName:Type.Optional(Type.String({maxLength:100})),createProfile:Type.Optional(Type.Boolean())}),RegisterResponseSchema=Type.Object({success:Type.Boolean(),message:Type.Optional(Type.String()),data:Type.Optional(Type.Object({user:Type.Object({id:Type.String(),email:Type.String()})}))})});import{eq as eq62}from"drizzle-orm";function createRegisterRoute(config,registerConfig,sendWelcomeEmail,signAccessToken,signRefreshToken,createSession,cookieConfig,tokenResponseConfig,getEmailService,appName,saveSessionToDb){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_REGISTER),route=registerConfig.route||"/auth/register",cookies={accessTokenName:cookieConfig?.accessTokenName||"access_token",refreshTokenName:cookieConfig?.refreshTokenName||"refresh_token",sessionTokenName:cookieConfig?.sessionTokenName||"session_token",accessTokenMaxAge:cookieConfig?.accessTokenMaxAge||900,refreshTokenMaxAge:cookieConfig?.refreshTokenMaxAge||604800,sessionTokenMaxAge:cookieConfig?.sessionTokenMaxAge||900,secure:cookieConfig?.secure??!0,httpOnly:cookieConfig?.httpOnly??!0,sameSite:cookieConfig?.sameSite||"strict",path:cookieConfig?.path||"/",domain:cookieConfig?.domain};if(!registerConfig.enabled)return collectRoutes();let routePostRoute=defineRoute({method:"POST",path:"/",body:RegisterBodySchema,detail:{tags:["Authentication"],summary:"Register",description:"Register a new user account"},handler:async(ctx)=>{let resolved=resolveAuthTablesForRequest(ctx.request,config),usersTable=resolved.usersTable;if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{email:rawEmail,password:password4,confirmPassword,firstName,lastName,createProfile}=ctx.body,email=rawEmail.toLowerCase();if(confirmPassword&&password4!==confirmPassword)return ctx.set.status=400,{success:!1,message:"Passwords do not match"};let passwordValidation=validatePasswordStrength(password4,config.authentication?.passwordPolicy,email);if(!passwordValidation.valid)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:passwordValidation.errors};let existingUsers=await db.select().from(usersTable).where(eq62(usersTable.email,email)).limit(1),reqUrl=new URL(ctx.request.url),auditIp=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",auditUa=ctx.request.headers.get("user-agent")||"unknown";if(existingUsers.length>0){log4.warn("Registration failed - email exists",{email}),logger2.audit({entityName:"users",operation:"REGISTER_FAILED",summary:`Registration failed: email already exists (${email})`,ipAddress:auditIp,userAgent:auditUa,path:reqUrl.pathname,query:reqUrl.search});let verifGatesSignup=registerConfig.emailVerification?.enabled&&getEmailService?.()?.isAvailable();if(config.authentication?.preventUserEnumeration&&verifGatesSignup)return{success:!0,message:"Registration successful. Please check your email to verify your account."};return ctx.set.status=409,{success:!1,message:"Email already registered"}}let hashedPassword=await hashPassword(password4),domainExempt=isEmailExempt(email,config.authentication?.emailExemptDomains),emailService=getEmailService?.()??null,emailVerificationEnabled=!domainExempt&®isterConfig.emailVerification?.enabled&&emailService?.isAvailable(),verificationToken=emailVerificationEnabled?generateVerificationToken():null,tokenExpiresIn=registerConfig.emailVerification?.tokenExpiresIn||"24h",tokenExpiresAt=emailVerificationEnabled?new Date(Date.now()+parseTimeToMs(tokenExpiresIn)):null,insertValues={email,password:hashedPassword};if(emailVerificationEnabled&&verificationToken)insertValues.emailVerificationToken=hashVerificationToken(verificationToken),insertValues.emailVerificationTokenExpiresAt=tokenExpiresAt,insertValues.emailVerificationSentAt=new Date,insertValues.emailVerificationAttempts=1;let newUser=(await db.insert(usersTable).values(insertValues).returning())[0],registerDefaultRoles=resolveDefaultRoleNames(config.authentication);if(registerDefaultRoles.length>0)await assignDefaultRoles({db,userId:newUser.id,roleNames:registerDefaultRoles,rolesTable:resolved.rolesTable??config.rolesTable??null,userRolesTable:resolved.userRolesTable??config.userRolesTable??null,logger:logger2});let wantsProfile=registerConfig.createProfileOnRegister||createProfile,profilesTable=resolved.schemaTables?.profiles;if(wantsProfile&&profilesTable&&(firstName||lastName))try{let profileNow=new Date;await db.insert(profilesTable).values({userId:newUser.id,firstName:firstName??"",lastName:lastName??"",createdAt:profileNow,updatedAt:profileNow})}catch(err){log4.warn("Failed to create profile on register \u2014 continuing",{userId:newUser.id,error:err instanceof Error?err.message:String(err)})}if(log4.info("Registration successful",{userId:newUser.id,email,emailVerificationEnabled}),logger2.audit({entityName:"users",entityId:newUser.id,operation:"REGISTER",userId:newUser.id,summary:`New user registered: ${email}`,ipAddress:auditIp,userAgent:auditUa,path:reqUrl.pathname,query:reqUrl.search}),emailVerificationEnabled&&emailService&&verificationToken){let verificationLink=buildEmailActionLink({request:ctx.request,configuredUrl:registerConfig.emailVerification?.redirectUrl,path:"/verify-email",query:{token:verificationToken},allowedOrigins:config.authentication?.trustedAppOrigins});emailService.sendVerificationEmail(email,email.split("@")[0]||"User",verificationLink,appName||"Nucleus",config.authentication?.emailVerificationTemplates?.verification?.subject).then((result2)=>{if(result2.success)log4.info("Verification email sent",{email});else log4.error("Failed to send verification email",{email,error:result2.error})}).catch((err)=>{log4.error("Failed to send verification email",{email,error:err})});let resendCooldown=registerConfig.emailVerification?.resendCooldown||"60s",cooldownSeconds=parseTimeToMs(resendCooldown)/1000,maxResendAttempts=registerConfig.emailVerification?.maxResendAttempts||3;if(config.authentication?.preventUserEnumeration)return{success:!0,message:"Registration successful. Please check your email to verify your account."};return{success:!0,message:"Registration successful. Please check your email to verify your account.",data:{user:{id:newUser.id,email:newUser.email},emailVerificationRequired:!0,verification:{cooldownSeconds,canResendAt:new Date(Date.now()+cooldownSeconds*1000).toISOString(),attemptsRemaining:maxResendAttempts-1,maxAttempts:maxResendAttempts}}}}if(sendWelcomeEmail)sendWelcomeEmail(email,firstName||email.split("@")[0]||"User").catch((err)=>{log4.error("Failed to send welcome email",{email,error:err})});if(signAccessToken&&signRefreshToken&&createSession){let ipAddress=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent=ctx.request.headers.get("user-agent")||"",sessionParams={userId:newUser.id,deviceInfo:ensureDeviceInfo({ipAddress,userAgent},deviceContextFromRequest(ctx.request).clientHints),loginMethod:"register",rememberMe:!0},sessionId=await createSession(sessionParams),accessToken=signAccessToken(newUser.id,void 0,void 0,ctx.request.headers.get("x-tenant-schema")??void 0,void 0,sessionId),refreshToken=signRefreshToken(newUser.id,void 0,sessionId),deviceTokenCookie;if(saveSessionToDb){let reqSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,dtCfg=config.authentication?.deviceTrust;if(dtCfg?.enabled)sessionParams.deviceToken=readDeviceTokenFromCookieHeader(ctx.request.headers.get("cookie"),dtCfg);deviceTokenCookie=(await saveSessionToDb(sessionId,sessionParams,reqSchemaName))?.deviceTokenCookie}let tokenConfig={accessToken:{setHeadersEnabled:tokenResponseConfig?.accessToken?.setHeadersEnabled??!0,returnJson:tokenResponseConfig?.accessToken?.returnJson??!0},refreshToken:{setHeadersEnabled:tokenResponseConfig?.refreshToken?.setHeadersEnabled??!0,returnJson:tokenResponseConfig?.refreshToken?.returnJson??!0},sessionToken:{setHeadersEnabled:tokenResponseConfig?.sessionToken?.setHeadersEnabled??!0,returnJson:tokenResponseConfig?.sessionToken?.returnJson??!0}},securePart=cookies.secure?"; Secure":"",domainPart=cookies.domain?`; Domain=${cookies.domain}`:"",cookieOptions=`; Path=${cookies.path}; HttpOnly; SameSite=${cookies.sameSite}${securePart}${domainPart}`,cookiesToSet=[];if(tokenConfig.accessToken.setHeadersEnabled)cookiesToSet.push(`${cookies.accessTokenName}=${accessToken}${cookieOptions}; Max-Age=${cookies.accessTokenMaxAge}`);if(tokenConfig.refreshToken.setHeadersEnabled)cookiesToSet.push(`${cookies.refreshTokenName}=${refreshToken}${cookieOptions}; Max-Age=${cookies.refreshTokenMaxAge}`);if(tokenConfig.sessionToken.setHeadersEnabled)cookiesToSet.push(`${cookies.sessionTokenName}=${sessionId}${cookieOptions}; Max-Age=${cookies.sessionTokenMaxAge}`);if(deviceTokenCookie)cookiesToSet.push(deviceTokenCookie);let responseData={user:{id:newUser.id,email:newUser.email}};if(tokenConfig.accessToken.returnJson)responseData.accessToken=accessToken;if(tokenConfig.refreshToken.returnJson)responseData.refreshToken=refreshToken;if(tokenConfig.sessionToken.returnJson)responseData.sessionId=sessionId;let jsonBody=JSON.stringify(withEnvelopeFlags({success:!0,data:responseData})),headers=new Headers;headers.set("Content-Type","application/json"),headers.set("x-session-id",sessionId);for(let cookie of cookiesToSet)headers.append("Set-Cookie",cookie);return new Response(jsonBody,{status:200,headers})}return{success:!0,data:{user:{id:newUser.id,email:newUser.email}}}}});return collectRoutes([{prefix:route,routes:[routePostRoute]}])}var init_register=__esm(()=>{init_DeviceTrust();init_scopes();init_response();init_routeCollector();init_assignDefaultRole();init_deviceInfo();init_types19();init_utils6();init_types19()});var SessionResponseSchema,SessionListResponseSchema,RevokeSessionBodySchema,RevokeAllSessionsBodySchema,SessionActivityResponseSchema,AdminRevokeSessionsBodySchema;var init_types20=__esm(()=>{init_esm3();SessionResponseSchema=Type.Object({id:Type.String(),deviceName:Type.Optional(Type.String()),deviceType:Type.Optional(Type.String()),browserName:Type.Optional(Type.String()),browserVersion:Type.Optional(Type.String()),osName:Type.Optional(Type.String()),osVersion:Type.Optional(Type.String()),ipAddress:Type.String(),locationCountry:Type.Optional(Type.String()),locationCity:Type.Optional(Type.String()),lastActivityAt:Type.String(),createdAt:Type.String(),isCurrent:Type.Boolean(),loginMethod:Type.Optional(Type.String()),trustScore:Type.Optional(Type.Number())}),SessionListResponseSchema=Type.Object({success:Type.Boolean(),data:Type.Optional(Type.Object({sessions:Type.Array(SessionResponseSchema),currentSessionId:Type.Optional(Type.String()),totalCount:Type.Number()})),message:Type.Optional(Type.String())}),RevokeSessionBodySchema=Type.Object({reason:Type.Optional(Type.String())}),RevokeAllSessionsBodySchema=Type.Object({excludeCurrent:Type.Optional(Type.Boolean()),reason:Type.Optional(Type.String())}),SessionActivityResponseSchema=Type.Object({success:Type.Boolean(),data:Type.Optional(Type.Object({recentActivity:Type.Array(Type.Object({sessionId:Type.String(),action:Type.String(),ipAddress:Type.String(),timestamp:Type.String(),deviceInfo:Type.Optional(Type.String())}))})),message:Type.Optional(Type.String())}),AdminRevokeSessionsBodySchema=Type.Optional(Type.Object({sessionId:Type.Optional(Type.String()),reason:Type.Optional(Type.String())}))});function formatSessionForResponse(session){let get=(snake,camel3)=>session[snake]??session[camel3],getDate=(snake,camel3)=>{let val=session[snake]??session[camel3];if(!val)return;return val instanceof Date?val.toISOString():String(val)};return{id:session.id,deviceName:get("device_name","deviceName"),deviceType:get("device_type","deviceType"),deviceFingerprint:get("device_fingerprint","deviceFingerprint"),browserName:get("browser_name","browserName"),browserVersion:get("browser_version","browserVersion"),osName:get("os_name","osName"),osVersion:get("os_version","osVersion"),ipAddress:get("ip_address","ipAddress"),locationCountry:get("location_country","locationCountry"),locationCity:get("location_city","locationCity"),lastActivityAt:getDate("last_activity_at","lastActivityAt"),createdAt:getDate("created_at","createdAt"),isCurrent:get("is_current","isCurrent"),loginMethod:get("login_method","loginMethod"),trustScore:get("trust_score","trustScore")}}var init_utils11=()=>{};import{and as and27,desc as desc6,eq as eq63,isNull as isNull5}from"drizzle-orm";function createSessionsRoute(config,sessionsConfig,sessionsTable){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_SESSION),baseRoute=sessionsConfig.route||"/auth/sessions";if(!sessionsConfig.enabled||!sessionsTable)return collectRoutes();let tableColumns=sessionsTable,_col=(name2)=>{let snakeCase=name2.replace(/([A-Z])/g,"_$1").toLowerCase();return tableColumns[name2]||tableColumns[snakeCase]},getSessionsForRequest=(request)=>{let resolved=resolveAuthTablesForRequest(request,config),reqTable=resolved.sessionsTable||sessionsTable,reqCols=reqTable,reqCol=(name2)=>{let snakeCase=name2.replace(/([A-Z])/g,"_$1").toLowerCase();return reqCols[name2]||reqCols[snakeCase]},trustedDevicesTable=resolved.schemaTables?.trustedDevices??resolved.schemaTables?.trusted_devices;return{sessionsTable:reqTable,col:reqCol,trustedDevicesTable}},routeGetRoot=defineRoute({method:"GET",path:"/",detail:{tags:["Authentication"],summary:"List active sessions",description:"Get all active sessions for the current user"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let currentSessionId=ctx.request.headers.get("x-session-id"),sessions=await db.select().from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0),isNull5(col15("revokedAt")))).orderBy(desc6(col15("lastActivityAt"))),realSessions=sessions.filter((s)=>{let sess=s,fp=(sess.deviceFingerprint||"").toLowerCase(),ip=sess.ipAddress||"";return!((!fp||fp==="--"||fp==="--unknown"||fp.includes("bot/crawler")||fp.includes("headless")||fp.includes("unknown-unknown"))&&(ip==="127.0.0.1"||ip==="::1"||ip==="localhost"||!ip))}),formattedSessions=realSessions.map((s)=>{let session=s,formatted=formatSessionForResponse(session);return formatted.isCurrent=session.id===currentSessionId,formatted});return log4.info("Sessions list retrieved",{userId,totalInDb:sessions.length,filteredCount:realSessions.length,hiddenBotSessions:sessions.length-realSessions.length}),{success:!0,data:{sessions:formattedSessions,currentSessionId,totalCount:realSessions.length}}}}),routeGetCurrent=defineRoute({method:"GET",path:"/current",detail:{tags:["Authentication"],summary:"Get current session",description:"Get details of the current session"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id"),sessionId=ctx.request.headers.get("x-session-id");if(!userId||!sessionId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let sessions=await db.select().from(sessionsTable2).where(eq63(col15("id"),sessionId)).limit(1);if(sessions.length===0)return ctx.set.status=404,{success:!1,message:"Session not found"};let session=sessions[0],formatted=formatSessionForResponse(session);return formatted.isCurrent=!0,{success:!0,data:formatted}}}),routeDeleteSessionid=defineRoute({method:"DELETE",path:"/:sessionId",body:RevokeSessionBodySchema,detail:{tags:["Authentication"],summary:"Revoke session",description:"Revoke a specific session by ID"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{sessionId}=ctx.params,body=ctx.body,currentSessionId=ctx.request.headers.get("x-session-id");if((await db.select().from(sessionsTable2).where(and27(eq63(col15("id"),sessionId),eq63(col15("userId"),userId))).limit(1)).length===0)return ctx.set.status=404,{success:!1,message:"Session not found"};let isCurrentSession=sessionId===currentSessionId;await db.update(sessionsTable2).set({isActive:!1,revokedAt:new Date,revokedReason:isCurrentSession?"user_logout":body.reason||"user_revoked"}).where(eq63(col15("id"),sessionId)),log4.info("Session revoked",{userId,sessionId,isCurrentSession,reason:body.reason||"user_revoked"});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"user_sessions",entityId:sessionId,operation:isCurrentSession?"LOGOUT":"SESSION_REVOKE",userId:userId||void 0,summary:isCurrentSession?"User logged out via session revoke":`Session revoked (${sessionId.substring(0,8)}...)`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:isCurrentSession?"Logged out successfully":"Session revoked successfully"}}}),routeDeleteAll=defineRoute({method:"DELETE",path:"/all",body:RevokeAllSessionsBodySchema,detail:{tags:["Authentication"],summary:"Revoke all sessions",description:"Revoke all sessions for the current user (optionally exclude current)"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let body=ctx.body,currentSessionId=ctx.request.headers.get("x-session-id"),query=db.update(sessionsTable2).set({isActive:!1,revokedAt:new Date,revokedReason:body.reason||"user_revoked"}).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0)));if(body.excludeCurrent&¤tSessionId){let{ne:ne4}=await import("drizzle-orm");query=db.update(sessionsTable2).set({isActive:!1,revokedAt:new Date,revokedReason:body.reason||"user_revoked"}).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0),ne4(col15("id"),currentSessionId)))}await query,log4.info("All sessions revoked",{userId,excludeCurrent:body.excludeCurrent,reason:body.reason||"user_revoked"});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"user_sessions",operation:"SESSION_REVOKE_ALL",userId:userId||void 0,summary:body.excludeCurrent?"All other sessions revoked":"All sessions revoked",ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:body.excludeCurrent?"All other sessions revoked successfully":"All sessions revoked successfully"}}}),routeGetStats=defineRoute({method:"GET",path:"/stats",detail:{tags:["Authentication"],summary:"Session statistics",description:"Get session statistics for the current user"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{count:count3,countDistinct}=await import("drizzle-orm"),activeSessions=await db.select({count:count3()}).from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0),isNull5(col15("revokedAt")))),uniqueDevices=await db.select({count:countDistinct(col15("deviceFingerprint"))}).from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0))),uniqueIps=await db.select({count:countDistinct(col15("ipAddress"))}).from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0)));return{success:!0,data:{activeSessions:activeSessions[0]?.count||0,uniqueDevices:uniqueDevices[0]?.count||0,uniqueIpAddresses:uniqueIps[0]?.count||0}}}}),APPROVAL_TOKEN_TTL_MS=86400000,buildResultHtml=(action,success,message)=>{let icon=success?action==="approve"?"\u2705":"\uD83D\uDEAB":"\u274C",title=success?action==="approve"?"Device Approved":"Device Rejected":"Action Failed",bName=sessionsConfig.brandName||"Nucleus";return`<!DOCTYPE html>
|
|
452
|
+
`}),logger2.info("[OAUTH] Invite email sent to new OAuth user",{userId,email:profile.email,provider})}catch(emailErr){logger2.warn("[OAUTH] Failed to send invite email",{userId,error:emailErr})}}{let stateUser=(await db.select().from(usersTable).where(eq57(usersTable.id,userId)).limit(1))[0],state2=stateUser?evaluateAccountState(stateUser):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!state2.allowed)return logger2.warn(`[OAUTH] Login blocked - account ${state2.reason}`,{userId,provider}),ctx.set.status=302,ctx.set.headers.Location=`${errorRedirect}?error=account_${state2.reason}`,null}let defaultRoleNames=resolveDefaultRoleNames(config.authentication);if(defaultRoleNames.length>0){let resolvedForRole=resolveAuthTablesForRequest(ctx.request,config);await assignDefaultRoles({db,userId,roleNames:defaultRoleNames,rolesTable:resolvedForRole.rolesTable??config.rolesTable??null,userRolesTable:resolvedForRole.userRolesTable??config.userRolesTable??null,logger:logger2})}let syncConfig=oauthService.profileSync;if(syncConfig){let syncTables=resolveAuthTablesForRequest(ctx.request,config);await applyProfileSync({db,usersTable,profilesTable:syncTables.schemaTables?.profiles,userId,rawProfile:profile.rawProfile,config:syncConfig,isNewUser:createdNewUser,logger:logger2})}await db.update(usersTable).set({lastLoginAt:new Date}).where(eq57(usersTable.id,userId));let ipAddress=ctx.request.headers.get("cf-connecting-ip")?.trim()||ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"127.0.0.1",userAgent=ctx.request.headers.get("user-agent")||"Unknown Browser",deviceInfo=parseUserAgentForLogin(userAgent,ipAddress,void 0,deviceContextFromRequest(ctx.request).clientHints),oauthUserRoles=[],oauthUserClaims=[],oauthUserClaimScopes={};if(config.db)try{let resolved2=resolveAuthTablesForRequest(ctx.request,config),rc=await fetchUserRolesAndClaims(config.db,userId,resolved2);oauthUserRoles=rc.roles,oauthUserClaims=rc.claims,oauthUserClaimScopes=rc.claimScopes}catch{}let requestOrigin=ctx.request.headers.get("origin")||ctx.request.headers.get("referer")?.replace(/\/[^/]*$/,"")||void 0,sessionParams={userId,deviceInfo,loginMethod:`oauth:${provider}`,rememberMe:!0,requestOrigin},sessionId=await createSession(sessionParams),accessToken=signAccessToken(userId,oauthUserRoles.length>0?oauthUserRoles:void 0,oauthUserClaims.length>0?oauthUserClaims:void 0,ctx.request.headers.get("x-tenant-schema")??void 0,oauthUserClaimScopes,sessionId),refreshToken=signRefreshToken(userId,void 0,sessionId),requiresApproval=!1,approvalSessionId=sessionId,deviceTokenCookie;if(saveSessionToDb){let oauthSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,dtCfg=config.authentication?.deviceTrust;if(dtCfg?.enabled)sessionParams.deviceToken=readDeviceTokenFromCookieHeader(ctx.request.headers.get("cookie"),dtCfg);let saveResult=await saveSessionToDb(sessionId,sessionParams,oauthSchemaName);if(saveResult?.denied)return logger2.warn("[OAUTH] Login blocked by device-trust",{userId,provider}),ctx.set.status=302,ctx.set.headers.Location=`${errorRedirect}?error=device_not_recognized`,null;if(deviceTokenCookie=saveResult?.deviceTokenCookie,saveResult?.requiresApproval){if(requiresApproval=!0,saveResult.sessionId)approvalSessionId=saveResult.sessionId}}if(requiresApproval){if(deviceTokenCookie)ctx.set.headers["Set-Cookie"]=deviceTokenCookie;logger2.info("[OAUTH] Login requires device approval",{userId,provider,approvalSessionId});let pendingUrl=absolutizeRedirect(resolveSafeOAuthRedirect(statePayload.redirectUrl,oauthService.successRedirectUrl,config.authentication?.trustedAppOrigins),portalOrigin);return ctx.set.status=302,ctx.set.headers.Location=`${pendingUrl}?requires_approval=true&provider=${provider}&session_id=${approvalSessionId}`,null}await logger2.audit({entityName:"users",entityId:userId,operation:"LOGIN",userId,summary:`${profile.email??profile.providerAccountId} logged in via OAuth (${provider})`,ipAddress,userAgent,path:`${basePath}/${provider}/callback`,query:""});let securePart=cookies.secure?"; Secure":"",domainPart=cookies.domain?`; Domain=${cookies.domain}`:"",cookieOptions=`; Path=${cookies.path}; HttpOnly; SameSite=${cookies.sameSite}${securePart}${domainPart}`,cookiesToSet=[];if(tokenConfig.accessToken.setHeadersEnabled)cookiesToSet.push(`${cookies.accessTokenName}=${accessToken}${cookieOptions}; Max-Age=${cookies.accessTokenMaxAge}`);if(tokenConfig.refreshToken.setHeadersEnabled)cookiesToSet.push(`${cookies.refreshTokenName}=${refreshToken}${cookieOptions}; Max-Age=${cookies.refreshTokenMaxAge}`);if(tokenConfig.sessionToken.setHeadersEnabled)cookiesToSet.push(`${cookies.sessionTokenName}=${sessionId}${cookieOptions}; Max-Age=${cookies.sessionTokenMaxAge}`);if(deviceTokenCookie)cookiesToSet.push(deviceTokenCookie);let successUrl=absolutizeRedirect(resolveSafeOAuthRedirect(statePayload.redirectUrl,oauthService.successRedirectUrl,config.authentication?.trustedAppOrigins),portalOrigin),headers=new Headers;headers.set("Location",successUrl);for(let cookie of cookiesToSet)headers.append("Set-Cookie",cookie);return new Response(null,{status:302,headers})}}),routeGetProviders=defineRoute({method:"GET",path:"/providers",detail:{tags:["Authentication"],summary:"List OAuth Providers",description:"Returns the list of enabled OAuth providers"},handler:()=>{return{success:!0,data:{providers:oauthService.getEnabledProviders()}}}}),routeGetLinkProvider=defineRoute({method:"GET",path:"/link/:provider",detail:{tags:["Authentication"],summary:"Link OAuth Account",description:"Redirects to provider to link an OAuth account to the current user"},handler:async(ctx)=>{let provider=ctx.params.provider;if(!oauthService.isProviderEnabled(provider))return ctx.set.status=404,{success:!1,message:`OAuth provider "${provider}" is not enabled`};if(!oauthService.allowAccountLinking)return ctx.set.status=403,{success:!1,message:"Account linking is disabled"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required to link accounts"};let redirectUrl=ctx.query.redirect_url,authUrl=await oauthService.buildAuthorizationUrl(provider,userId,redirectUrl),issuedState=new URL(authUrl).searchParams.get("state");if(issuedState)ctx.set.headers["Set-Cookie"]=buildOAuthStateCookie(issuedState,{maxAge:600,secure:cookies.secure,domain:cookies.domain});return ctx.set.status=302,ctx.set.headers.Location=authUrl,null}}),routeDeleteUnlinkProvider=defineRoute({method:"DELETE",path:"/unlink/:provider",detail:{tags:["Authentication"],summary:"Unlink OAuth Account",description:"Removes a linked OAuth account from the current user"},handler:async(ctx)=>{let provider=ctx.params.provider,userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let oauthTable=config.oauthAccountsTable;if(!oauthTable)return ctx.set.status=500,{success:!1,message:"OAuth accounts table not configured"};if((await db.select().from(oauthTable).where(and25(eq57(oauthTable.userId,userId),eq57(oauthTable.provider,provider))).limit(1)).length===0)return ctx.set.status=404,{success:!1,message:`No linked ${provider} account found`};let{usersTable:resolvedUsersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!resolvedUsersTable)return ctx.set.status=500,{success:!1,message:"Users table not configured"};let hasPassword=!!(await db.select().from(resolvedUsersTable).where(eq57(resolvedUsersTable.id,userId)).limit(1))[0]?.password,allOAuthAccounts=await db.select().from(oauthTable).where(eq57(oauthTable.userId,userId));if(!hasPassword&&allOAuthAccounts.length<=1)return ctx.set.status=400,{success:!1,message:"Cannot unlink the only login method. Set a password first."};return await db.delete(oauthTable).where(and25(eq57(oauthTable.userId,userId),eq57(oauthTable.provider,provider))),logger2.info("[OAUTH] Account unlinked",{userId,provider}),{success:!0,message:`${provider} account unlinked successfully`}}}),routeGetAccounts=defineRoute({method:"GET",path:"/accounts",detail:{tags:["Authentication"],summary:"List Linked OAuth Accounts",description:"Returns all OAuth accounts linked to the current user"},handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let oauthTable=config.oauthAccountsTable;if(!oauthTable)return{success:!0,data:{accounts:[]}};return{success:!0,data:{accounts:(await db.select().from(oauthTable).where(eq57(oauthTable.userId,userId))).map((a)=>({id:a.id,provider:a.provider,providerEmail:a.providerEmail,providerName:a.providerName,providerAvatarUrl:a.providerAvatarUrl,isPrimary:a.isPrimary,lastUsedAt:a.lastUsedAt,createdAt:a.createdAt}))}}}});return collectRoutes([{prefix:basePath,routes:[routeGetProvider,routeGetProviderCallback,routeGetProviders,routeGetLinkProvider,routeDeleteUnlinkProvider,routeGetAccounts]}])}var OAUTH_STATE_COOKIE="oauth_state",readCookie=(request,name2)=>{let raw=request.headers.get("cookie");if(!raw)return;for(let part of raw.split(";")){let trimmed=part.trim(),eq58=trimmed.indexOf("=");if(eq58>0&&trimmed.slice(0,eq58)===name2)return trimmed.slice(eq58+1)}return},resolveSafeOAuthRedirect=(candidate,fallback,allowedOrigins)=>{if(!candidate)return fallback;let normalized=candidate.replace(/[\t\n\r]/g,"");if(!normalized)return fallback;if(normalized.startsWith("/")&&normalized[1]!=="/"&&normalized[1]!=="\\")return normalized;try{let candHost=new URL(normalized).host.toLowerCase(),trusted=[];try{trusted.push(new URL(fallback).host.toLowerCase())}catch{}for(let o of allowedOrigins??[])try{trusted.push(new URL(o.includes("://")?o:`https://${o}`).host.toLowerCase())}catch{}for(let t of trusted)if(t.startsWith("*.")){let base=t.slice(2);if(candHost===base||candHost.endsWith(`.${base}`))return normalized}else if(candHost===t)return normalized}catch{}return fallback},absolutizeRedirect=(target2,portalOrigin)=>portalOrigin&&target2.startsWith("/")&&target2[1]!=="/"?`${portalOrigin}${target2}`:target2;var init_oauth=__esm(()=>{init_DeviceTrust();init_routeCollector();init_assignDefaultRole();init_fetchUserRolesAndClaims();init_deviceInfo();init_utils7();init_utils8();init_applyProfileSync()});var PasswordChangeBodySchema,PasswordChangeResponseSchema;var init_types15=__esm(()=>{init_esm3();PasswordChangeBodySchema=Type.Object({currentPassword:Type.Optional(Type.String()),newPassword:Type.String({minLength:8}),confirmPassword:Type.String({minLength:8})}),PasswordChangeResponseSchema=Type.Object({success:Type.Boolean(),message:Type.Optional(Type.String())})});function validatePasswordsMatch(newPassword,confirmPassword){return newPassword===confirmPassword}var exports_store={};__export(exports_store,{userHasNoTrustedDevices:()=>userHasNoTrustedDevices,touchDevice:()=>touchDevice,revokeUserDevices:()=>revokeUserDevices,revokeDevicesBySessionIds:()=>revokeDevicesBySessionIds,revokeDeviceById:()=>revokeDeviceById,rejectDeviceForSession:()=>rejectDeviceForSession,listUserDevices:()=>listUserDevices,insertDeviceRow:()=>insertDeviceRow,findDeviceRowsByRawToken:()=>findDeviceRowsByRawToken,activateDeviceForSession:()=>activateDeviceForSession});import{and as and26,eq as eq58,inArray as inArray19}from"drizzle-orm";async function findDeviceRowsByRawToken(db,table,rawToken){let hash=hashDeviceToken(rawToken);return await db.select().from(table).where(eq58(col14(table,"tokenHash"),hash)).limit(2)}async function insertDeviceRow(db,table,v){let now=new Date;await db.insert(table).values({id:v.id,userId:v.userId,tokenHash:v.tokenHash,status:v.status,originSessionId:v.originSessionId??null,label:v.label??null,deviceFingerprint:v.deviceFingerprint??null,firstSeenIp:v.firstSeenIp??null,lastSeenIp:v.lastSeenIp??v.firstSeenIp??null,lastSeenAt:now,expiresAt:v.expiresAt,isActive:!0,createdAt:now,updatedAt:now})}async function activateDeviceForSession(db,table,sessionId){return(await db.update(table).set({status:"trusted",updatedAt:new Date}).where(and26(eq58(col14(table,"originSessionId"),sessionId),eq58(col14(table,"status"),"pending"))).returning({id:col14(table,"id")})).length}async function rejectDeviceForSession(db,table,sessionId){await db.update(table).set({status:"revoked",revokedAt:new Date,revokedReason:"replaced",isActive:!1,updatedAt:new Date}).where(and26(eq58(col14(table,"originSessionId"),sessionId),eq58(col14(table,"status"),"pending")))}async function touchDevice(db,table,id,ip){await db.update(table).set({lastSeenAt:new Date,lastSeenIp:ip??null,updatedAt:new Date}).where(eq58(col14(table,"id"),id))}async function revokeWhere(db,table,where,reason){await db.update(table).set({status:"revoked",revokedAt:new Date,revokedReason:reason,isActive:!1,updatedAt:new Date}).where(where)}async function revokeUserDevices(db,table,userId,reason){if(!userId)return;let notAlready=and26(eq58(col14(table,"userId"),userId),eq58(col14(table,"status"),"trusted")),alsoPending=and26(eq58(col14(table,"userId"),userId),eq58(col14(table,"status"),"pending"));await revokeWhere(db,table,notAlready,reason),await revokeWhere(db,table,alsoPending,reason)}async function revokeDevicesBySessionIds(db,table,sessionIds,reason){if(!sessionIds?.length)return;await revokeWhere(db,table,inArray19(col14(table,"originSessionId"),sessionIds),reason)}async function revokeDeviceById(db,table,id,userId,reason){return(await db.update(table).set({status:"revoked",revokedAt:new Date,revokedReason:reason,isActive:!1,updatedAt:new Date}).where(and26(eq58(col14(table,"id"),id),eq58(col14(table,"userId"),userId))).returning({id:col14(table,"id")})).length}async function listUserDevices(db,table,userId){return(await db.select().from(table).where(eq58(col14(table,"userId"),userId))).map((r)=>{let{tokenHash:_omit,...safe}=r;return safe})}async function userHasNoTrustedDevices(db,table,userId){return(await db.select({id:col14(table,"id")}).from(table).where(and26(eq58(col14(table,"userId"),userId),eq58(col14(table,"status"),"trusted"))).limit(1)).length===0}var col14=(t,name2)=>t[name2];var init_store3=__esm(()=>{init_DeviceTrust()});import{eq as eq59}from"drizzle-orm";function createPasswordChangeRoute(config,passwordChangeConfig){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_PASSWORD_CHANGE),route=passwordChangeConfig.route||"/auth/password-change";if(!passwordChangeConfig.enabled)return collectRoutes();let routePostRoute=defineRoute({method:"POST",path:"/",body:PasswordChangeBodySchema,detail:{tags:["Authentication"],summary:"Change Password",description:"Change password for authenticated user"},handler:async(ctx)=>{let{usersTable,sessionsTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{currentPassword,newPassword,confirmPassword}=ctx.body;if(!validatePasswordsMatch(newPassword,confirmPassword))return ctx.set.status=422,{success:!1,message:"New passwords do not match"};let strength=validatePasswordStrength(newPassword,config.authentication?.passwordPolicy);if(!strength.valid)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:strength.errors};let user=(await db.select().from(usersTable).where(eq59(usersTable.id,userId)).limit(1))[0];if(!user)return ctx.set.status=404,{success:!1,message:"User not found"};let identityError=identityRuleError(newPassword,config.authentication?.passwordPolicy,typeof user.email==="string"?user.email:void 0);if(identityError)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:[identityError]};let existingHash=user.password??"",userHasPassword=existingHash.length>0,isInitialSet=!userHasPassword,reqUrl=new URL(ctx.request.url),auditIp=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",auditUa=ctx.request.headers.get("user-agent")||"unknown";if(userHasPassword){if(!currentPassword)return ctx.set.status=400,{success:!1,message:"Current password is required"};if(!await verifyPassword(currentPassword,existingHash))return log4.warn("Password change failed - invalid current password",{userId}),logger2.audit({entityName:"users",entityId:userId,operation:"PASSWORD_CHANGE_FAILED",userId,summary:"Password change failed: invalid current password",ipAddress:auditIp,userAgent:auditUa,path:reqUrl.pathname,query:reqUrl.search}),ctx.set.status=400,{success:!1,message:"Current password is incorrect"}}let hashedNewPassword=await hashPassword(newPassword);if(await db.update(usersTable).set({password:hashedNewPassword,updatedAt:new Date}).where(eq59(usersTable.id,userId)),!isInitialSet&&sessionsTable)try{let revoked=await db.update(sessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"password_change"}).where(eq59(sessionsTable.userId,userId)).returning({id:sessionsTable.id});await forgetSessionsInRedis(revoked.map((r)=>r.id))}catch(err){log4.warn("Failed to revoke sessions after password change",{userId,error:err instanceof Error?err.message:String(err)})}if(!isInitialSet&&config.authentication?.deviceTrust?.enabled)try{let{schemaTables}=resolveAuthTablesForRequest(ctx.request,config),dtTable=schemaTables?.trustedDevices??schemaTables?.trusted_devices;if(dtTable&&db){let{revokeUserDevices:revokeUserDevices2}=await Promise.resolve().then(() => (init_store3(),exports_store));await revokeUserDevices2(db,dtTable,userId,"password_reset")}}catch(err){log4.warn("Failed to revoke device tokens after password change",{userId,error:err instanceof Error?err.message:String(err)})}return log4.info(isInitialSet?"Initial password set successful":"Password change successful",{userId}),logger2.audit({entityName:"users",entityId:userId,operation:isInitialSet?"PASSWORD_SET":"PASSWORD_CHANGE",userId,summary:isInitialSet?"Initial password set successfully":"Password changed successfully",ipAddress:auditIp,userAgent:auditUa,path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:isInitialSet?"Password set successfully":"Password changed successfully"}}});return collectRoutes([{prefix:route,routes:[routePostRoute]}])}var init_passwordChange=__esm(()=>{init_Delete2();init_scopes();init_routeCollector();init_utils7();init_passwordPolicy();init_utils6();init_types15();init_types15()});function describeResetEmail(outcome){if(!outcome||outcome.sent)return{sent:!0,level:"info",message:"Password reset email sent"};let base=SENTENCES[outcome.reason],detail=outcome.detail?.trim();return{sent:!1,level:outcome.reason==="exempt"?"info":"warn",message:detail?`${base} (${detail})`:base}}var SENTENCES;var init_outcome=__esm(()=>{SENTENCES={no_provider:"Password reset email NOT sent \u2014 no email provider is configured. The token was stored, so a link exists, but nothing carried it.",exempt:"Password reset email not sent \u2014 the address is on an exempt domain this install never mails.",rejected:"Password reset email NOT sent \u2014 the provider refused the recipient. The address is accepted at login but not deliverable.",error:"Password reset email NOT sent \u2014 the send failed."}});var PasswordResetRequestSchema,PasswordResetConfirmSchema,PasswordResetResponseSchema;var init_types16=__esm(()=>{init_esm3();PasswordResetRequestSchema=Type.Object({email:Type.String({format:"email"})}),PasswordResetConfirmSchema=Type.Object({token:Type.String(),newPassword:Type.String({minLength:8}),confirmPassword:Type.String({minLength:8})}),PasswordResetResponseSchema=Type.Object({success:Type.Boolean(),message:Type.Optional(Type.String())})});import{randomBytes as randomBytes7}from"crypto";function generateResetToken(){return randomBytes7(32).toString("hex")}function isTokenExpired(expiresAt){return new Date>expiresAt}var init_utils10=()=>{};function createPasswordResetRoute(config,passwordResetConfig,storeResetToken,getResetToken,deleteResetToken,sendResetEmail){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_PASSWORD_RESET),baseRoute=passwordResetConfig.route||"/auth/password-reset";if(!passwordResetConfig.enabled)return collectRoutes();let routePostBaserouteRequest=defineRoute({method:"POST",path:"/request",body:PasswordResetRequestSchema,detail:{tags:["Authentication"],summary:"Request Password Reset",description:"Request a password reset email"},handler:async(ctx)=>{let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{email:rawEmail}=ctx.body,email=rawEmail.toLowerCase(),{eq:eq60}=await import("drizzle-orm"),user=(await db.select().from(usersTable).where(eq60(usersTable.email,email)).limit(1))[0];if(!user)return{success:!0,message:"If email exists, reset link will be sent"};let token=generateResetToken(),expiresAt=new Date(Date.now()+3600000),reqSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0;await storeResetToken(user.id,token,expiresAt,reqSchemaName);let delivery={sent:!1,level:"warn",message:"Password reset email NOT sent \u2014 no send helper is configured."};if(sendResetEmail)try{delivery=describeResetEmail(await sendResetEmail(email,token,ctx.request))}catch(error3){delivery=describeResetEmail({sent:!1,reason:"error",detail:error3 instanceof Error?error3.message:String(error3)})}if(delivery.level==="warn")log4.warn(delivery.message,{email});else log4.info(delivery.message,{email});log4.info("Password reset requested",{userId:user.id,email});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"users",entityId:user.id,operation:"PASSWORD_RESET_REQUEST",userId:user.id,summary:`Password reset requested for ${email} \u2014 ${delivery.sent?"email sent":"EMAIL NOT SENT"}`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:"If email exists, reset link will be sent"}}}),routePostBaserouteConfirm=defineRoute({method:"POST",path:"/confirm",body:PasswordResetConfirmSchema,detail:{tags:["Authentication"],summary:"Confirm Password Reset",description:"Reset password with token"},handler:async(ctx)=>{let{usersTable,sessionsTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{token,newPassword,confirmPassword}=ctx.body;if(newPassword!==confirmPassword)return ctx.set.status=400,{success:!1,message:"Passwords do not match"};let strength=validatePasswordStrength(newPassword,config.authentication?.passwordPolicy);if(!strength.valid)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:strength.errors};let reqSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,resetData=await getResetToken(token,reqSchemaName);if(!resetData)return ctx.set.status=400,{success:!1,message:"Invalid or expired reset token"};if(isTokenExpired(resetData.expiresAt))return await deleteResetToken(token,reqSchemaName),ctx.set.status=400,{success:!1,message:"Reset token has expired"};let{eq:eq60}=await import("drizzle-orm");if(config.authentication?.passwordPolicy?.preventUserInfoInPassword){let ownerEmail=(await db.select().from(usersTable).where(eq60(usersTable.id,resetData.userId)).limit(1))[0]?.email,identityError=identityRuleError(newPassword,config.authentication?.passwordPolicy,typeof ownerEmail==="string"?ownerEmail:void 0);if(identityError)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:[identityError]}}let hashedPassword=await hashPassword(newPassword);if(await db.update(usersTable).set({password:hashedPassword}).where(eq60(usersTable.id,resetData.userId)),await deleteResetToken(token,reqSchemaName),sessionsTable)try{let revoked=await db.update(sessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"password_reset"}).where(eq60(sessionsTable.userId,resetData.userId)).returning({id:sessionsTable.id});await forgetSessionsInRedis(revoked.map((r)=>r.id))}catch(err){log4.warn("Failed to revoke sessions after password reset",{userId:resetData.userId,error:err instanceof Error?err.message:String(err)})}try{if(config.authentication?.deviceTrust?.enabled){let{schemaTables}=resolveAuthTablesForRequest(ctx.request,config),dtTable=schemaTables?.trustedDevices??schemaTables?.trusted_devices;if(dtTable&&db){let{revokeUserDevices:revokeUserDevices2}=await Promise.resolve().then(() => (init_store3(),exports_store));await revokeUserDevices2(db,dtTable,resetData.userId,"password_reset")}}}catch(err){log4.warn("Failed to revoke device tokens after password reset",{userId:resetData.userId,error:err instanceof Error?err.message:String(err)})}log4.info("Password reset successful",{userId:resetData.userId});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"users",entityId:resetData.userId,operation:"PASSWORD_RESET",userId:resetData.userId,summary:"Password reset completed successfully",ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:"Password has been reset"}}});return collectRoutes([{prefix:baseRoute,routes:[routePostBaserouteRequest,routePostBaserouteConfirm]}])}var init_passwordReset=__esm(()=>{init_scopes();init_Delete2();init_routeCollector();init_passwordPolicy();init_utils6();init_outcome();init_types16();init_utils10();init_types16()});var PasswordSetBodySchema,PasswordSetResponseSchema;var init_types17=__esm(()=>{init_esm3();PasswordSetBodySchema=Type.Object({newPassword:Type.String({minLength:8}),userId:Type.Optional(Type.String()),token:Type.Optional(Type.String())}),PasswordSetResponseSchema=Type.Object({success:Type.Boolean(),message:Type.String()})});import{eq as eq60}from"drizzle-orm";function createPasswordSetRoute(config,passwordSetConfig,getMagicToken,deleteMagicToken){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_PASSWORD_SET),route=passwordSetConfig.route||"/auth/password-set";if(!passwordSetConfig.enabled)return collectRoutes();let routePostRoute=defineRoute({method:"POST",path:"/",body:PasswordSetBodySchema,detail:{tags:["Authentication"],summary:"Set Password",description:"Set password for the first time (for invited users who do not have a password yet)"},handler:async(ctx)=>{log4.info("Password set request received");let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return log4.error("Password set failed - database not configured"),ctx.set.status=500,{success:!1,message:"Database not configured"};let{newPassword,token}=ctx.body,strength=validatePasswordStrength(newPassword,config.authentication?.passwordPolicy);if(!strength.valid)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:strength.errors};let userId=null;if(token&&getMagicToken&&deleteMagicToken){let reqSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,tokenHash=hashToken(token,TOKEN_PURPOSE.invite),storedToken=await getMagicToken(tokenHash,reqSchemaName);if(!storedToken)return log4.warn("Password set failed - invalid token"),ctx.set.status=400,{success:!1,message:"Invalid or expired token"};if(new Date>storedToken.expiresAt)return await deleteMagicToken(tokenHash,reqSchemaName),log4.warn("Password set failed - expired token",{email:storedToken.email}),ctx.set.status=400,{success:!1,message:"Invalid or expired token"};userId=storedToken.userId,log4.info("Password set - userId resolved from token",{userId,email:storedToken.email})}else userId=ctx.request.headers.get("x-user-id");if(!userId)return log4.warn("Password set failed - no token and no authenticated user"),ctx.set.status=401,{success:!1,message:"Valid token or authentication required"};let user=(await db.select().from(usersTable).where(eq60(usersTable.id,userId)).limit(1))[0];if(log4.info("Password set - user found",{found:!!user,hasPassword:!!user?.password}),!user)return ctx.set.status=404,{success:!1,message:"User not found"};let identityError=identityRuleError(newPassword,config.authentication?.passwordPolicy,typeof user.email==="string"?user.email:void 0);if(identityError)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:[identityError]};if(user.password)return log4.warn("Password set failed - user already has password",{userId}),ctx.set.status=409,{success:!1,message:"Password already set. Use password change instead."};let hashedPassword=await hashPassword(newPassword);log4.info("Password set - updating user with verifiedAt",{userId});let updateResult=await db.update(usersTable).set({password:hashedPassword,verifiedAt:new Date,updatedAt:new Date}).where(eq60(usersTable.id,userId));if(log4.info("Password set successful for invited user",{userId,updateResult}),token&&deleteMagicToken){let setSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,tokenHash=hashToken(token,TOKEN_PURPOSE.invite);await deleteMagicToken(tokenHash,setSchemaName),log4.info("Invite token consumed after password set",{userId})}return{success:!0,message:"Password set successfully"}}});return collectRoutes([{prefix:route,routes:[routePostRoute]}])}var init_passwordSet=__esm(()=>{init_scopes();init_routeCollector();init_utils8();init_passwordPolicy();init_utils6();init_types17();init_types17()});function parseTimeToSeconds3(time2){let match=time2.match(/^(\d+)([smhd])$/);if(!match)return 900;let value2=match[1],unit=match[2];if(!value2||!unit)return 900;let num3=parseInt(value2,10);switch(unit){case"s":return num3;case"m":return num3*60;case"h":return num3*3600;case"d":return num3*86400;default:return 900}}var RefreshResponseSchema;var init_types18=__esm(()=>{init_esm3();RefreshResponseSchema=Type.Object({success:Type.Boolean(),message:Type.Optional(Type.String()),data:Type.Optional(Type.Object({accessToken:Type.String()}))})});import{eq as eq61}from"drizzle-orm";function createRefreshRoute(config,refreshConfig,verifyRefreshToken,signAccessToken,signRefreshToken,tokenResponseConfig,cookieMaxAgeBufferSeconds,cookieConfig){let{logger:logger2,authentication}=config,route=refreshConfig.route||"/auth/refresh";if(!refreshConfig.enabled)return collectRoutes();let routePostRoute=defineRoute({method:"POST",path:"/",detail:{tags:["Authentication"],summary:"Refresh Token",description:"Get a new access token using a refresh token. Browsers send it as the refresh cookie; a header-only client sends it as `Authorization: Bearer <refresh token>`."},handler:async(ctx)=>{let refreshTokenName=authentication?.refreshToken?.name||"refresh_token",accessTokenName=authentication?.accessToken?.name||"access_token",refreshToken=null,cookieHeader=ctx.request.headers.get("cookie");if(cookieHeader)refreshToken=cookieHeader.split(";").reduce((acc,cookie)=>{let trimmed=cookie.trim(),eqIndex=trimmed.indexOf("=");if(eqIndex>0)acc[trimmed.slice(0,eqIndex)]=trimmed.slice(eqIndex+1);return acc},{})[refreshTokenName]||null;if(!refreshToken){let authorization=ctx.request.headers.get("authorization")??"";refreshToken=/^Bearer\s+(.+)$/i.exec(authorization.trim())?.[1]?.trim()||null}if(!refreshToken)return logger2.debug("[AUTH] Refresh skipped - no refresh cookie or bearer token on the request"),ctx.set.status=401,{success:!1,message:"Refresh token required"};let result=verifyRefreshToken(refreshToken);if(!result.valid||!result.payload)return logger2.warn("[AUTH] Refresh failed - invalid token"),ctx.set.status=401,{success:!1,message:"Invalid refresh token"};let userId=result.payload.sub,resolved=resolveAuthTablesForRequest(ctx.request,config),statelessMode=authentication?.mode==="consumer",boundSessionId=typeof result.payload.sessionId==="string"?result.payload.sessionId:"",sessionRememberMe,supersededHash;if(!statelessMode){if(!boundSessionId)return logger2.warn("[AUTH] Refresh blocked - token carries no session",{userId}),ctx.set.status=401,{success:!1,message:"Refresh token is not bound to a session"};let session=await refreshSessionIsAlive({sessionId:boundSessionId,db:config.db,sessionsTable:resolved.sessionsTable});if(!session.alive)return logger2.warn("[AUTH] Refresh blocked - session is no longer active",{userId,sessionId:boundSessionId,reason:session.reason}),ctx.set.status=401,{success:!1,message:"Session is no longer active"};sessionRememberMe=session.rememberMe;let verdict=classifyRefreshToken({presentedHash:hashRefreshToken(refreshToken),currentHash:session.refreshTokenHash,previousHash:session.previousRefreshTokenHash,previousRotatedAt:session.previousRefreshTokenAt,nowMs:Date.now()});if(verdict.action==="revoke")return logger2.warn("[AUTH] Refresh token reuse detected - ending the session",{userId,sessionId:boundSessionId,reason:verdict.reason}),await deleteSession({sessionId:boundSessionId}).catch(()=>{return}),ctx.set.status=401,{success:!1,message:"Session is no longer active"};supersededHash=session.refreshTokenHash}let userRoles=[],userClaims=[],userClaimScopes={};if(config.db){try{let rc=await fetchUserRolesAndClaims(config.db,userId,resolved);userRoles=rc.roles,userClaims=rc.claims,userClaimScopes=rc.claimScopes}catch(roleError){logger2.error("[AUTH] Failed to fetch roles/claims during refresh",{userId,error:roleError instanceof Error?roleError.message:String(roleError)})}try{let usersTable=resolved.usersTable;if(usersTable){let user=(await config.db.select().from(usersTable).where(eq61(usersTable.id,userId)).limit(1))[0];if(!user||user.isActive===!1)return logger2.warn("[AUTH] Refresh blocked - account inactive",{userId}),ctx.set.status=401,{success:!1,message:"Account is not active"};let lockedUntilRaw=user.lockedUntil,lockedUntil=lockedUntilRaw?new Date(lockedUntilRaw):null;if(user.isLocked===!0&&(!lockedUntil||lockedUntil>new Date))return logger2.warn("[AUTH] Refresh blocked - account locked",{userId}),ctx.set.status=401,{success:!1,message:"Account is locked"};let userCohortId=user.cohortId;if(userCohortId){let cohortsTable=resolved.schemaTables?.userCohorts??resolved.schemaTables?.user_cohorts;if(cohortsTable){let cohortExpiresAt=(await config.db.select().from(cohortsTable).where(eq61(cohortsTable.id,userCohortId)).limit(1))[0]?.expiresAt;if(cohortExpiresAt&&new Date(cohortExpiresAt)<new Date)return logger2.warn("[AUTH] Refresh blocked - cohort expired",{userId,cohortId:userCohortId}),ctx.set.status=401,{success:!1,message:"Your access has expired. Please contact your administrator."}}}}}catch(cohortErr){logger2.error("[AUTH] Failed cohort expiry check during refresh",{userId,error:cohortErr instanceof Error?cohortErr.message:String(cohortErr)})}}let newAccessToken=signAccessToken(userId,userRoles.length>0?userRoles:void 0,userClaims.length>0?userClaims:void 0,ctx.request.headers.get("x-tenant-schema")??void 0,userClaimScopes,boundSessionId||void 0),newRefreshToken=signRefreshToken?signRefreshToken(userId,sessionRememberMe,boundSessionId||void 0):null;await recordIssuedRefreshToken(boundSessionId||void 0,newRefreshToken,{previousHash:supersededHash});let accessSetHeaders=tokenResponseConfig?.accessToken?.setHeadersEnabled??!0,accessReturnJson=tokenResponseConfig?.accessToken?.returnJson??!0,refreshSetHeaders=tokenResponseConfig?.refreshToken?.setHeadersEnabled??!0,refreshReturnJson=tokenResponseConfig?.refreshToken?.returnJson??!1,accessExpiresIn=authentication?.accessToken?.expiresIn||"15m",accessMaxAge=Math.max(0,parseTimeToSeconds3(accessExpiresIn)-(cookieMaxAgeBufferSeconds??0)),refreshTtl=longerLifetime(sessionRememberMe?authentication?.rememberMe?.expiresIn:void 0,authentication?.refreshToken?.expiresIn,604800),refreshMaxAge=cookieMaxAge(refreshTtl),headers=new Headers;headers.set("Content-Type","application/json");let cookiePath=cookieConfig?.path||"/",cookieSameSite=cookieConfig?.sameSite||"Strict",securePart=cookieConfig?.secure!==!1?"; Secure":"",domainPart=cookieConfig?.domain?`; Domain=${cookieConfig.domain}`:"",cookieOpts=`; Path=${cookiePath}; HttpOnly; SameSite=${cookieSameSite}${securePart}${domainPart}`;if(accessSetHeaders)headers.append("Set-Cookie",`${accessTokenName}=${newAccessToken}${cookieOpts}; Max-Age=${accessMaxAge}`);if(newRefreshToken&&refreshSetHeaders)headers.append("Set-Cookie",`${refreshTokenName}=${newRefreshToken}${cookieOpts}; Max-Age=${refreshMaxAge}`);logger2.info("[AUTH] Token refresh successful",{userId,rotatedRefreshToken:!!newRefreshToken});let responseData={};if(accessReturnJson)responseData.accessToken=newAccessToken;if(newRefreshToken&&refreshReturnJson)responseData.refreshToken=newRefreshToken;let jsonBody=JSON.stringify(withEnvelopeFlags({success:!0,data:responseData}));return new Response(jsonBody,{status:200,headers})}});return collectRoutes([{prefix:route,routes:[routePostRoute]}])}var init_refresh=__esm(()=>{init_Delete2();init_response();init_routeCollector();init_lifetime();init_fetchUserRolesAndClaims();init_recordIssued();init_reuseDetection();init_sessionBinding();init_types18()});var RegisterBodySchema,RegisterResponseSchema;var init_types19=__esm(()=>{init_esm3();RegisterBodySchema=Type.Object({email:Type.String({format:"email"}),password:Type.String({minLength:8}),confirmPassword:Type.Optional(Type.String({minLength:8})),firstName:Type.Optional(Type.String({maxLength:100})),lastName:Type.Optional(Type.String({maxLength:100})),createProfile:Type.Optional(Type.Boolean())}),RegisterResponseSchema=Type.Object({success:Type.Boolean(),message:Type.Optional(Type.String()),data:Type.Optional(Type.Object({user:Type.Object({id:Type.String(),email:Type.String()})}))})});import{eq as eq62}from"drizzle-orm";function createRegisterRoute(config,registerConfig,sendWelcomeEmail,signAccessToken,signRefreshToken,createSession,cookieConfig,tokenResponseConfig,getEmailService,appName,saveSessionToDb){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_REGISTER),route=registerConfig.route||"/auth/register",cookies={accessTokenName:cookieConfig?.accessTokenName||"access_token",refreshTokenName:cookieConfig?.refreshTokenName||"refresh_token",sessionTokenName:cookieConfig?.sessionTokenName||"session_token",accessTokenMaxAge:cookieConfig?.accessTokenMaxAge||900,refreshTokenMaxAge:cookieConfig?.refreshTokenMaxAge||604800,sessionTokenMaxAge:cookieConfig?.sessionTokenMaxAge||900,secure:cookieConfig?.secure??!0,httpOnly:cookieConfig?.httpOnly??!0,sameSite:cookieConfig?.sameSite||"strict",path:cookieConfig?.path||"/",domain:cookieConfig?.domain};if(!registerConfig.enabled)return collectRoutes();let routePostRoute=defineRoute({method:"POST",path:"/",body:RegisterBodySchema,detail:{tags:["Authentication"],summary:"Register",description:"Register a new user account"},handler:async(ctx)=>{let resolved=resolveAuthTablesForRequest(ctx.request,config),usersTable=resolved.usersTable;if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{email:rawEmail,password:password4,confirmPassword,firstName,lastName,createProfile}=ctx.body,email=rawEmail.toLowerCase();if(confirmPassword&&password4!==confirmPassword)return ctx.set.status=400,{success:!1,message:"Passwords do not match"};let passwordValidation=validatePasswordStrength(password4,config.authentication?.passwordPolicy,email);if(!passwordValidation.valid)return ctx.set.status=400,{success:!1,message:"Password too weak",errors:passwordValidation.errors};let existingUsers=await db.select().from(usersTable).where(eq62(usersTable.email,email)).limit(1),reqUrl=new URL(ctx.request.url),auditIp=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",auditUa=ctx.request.headers.get("user-agent")||"unknown";if(existingUsers.length>0){log4.warn("Registration failed - email exists",{email}),logger2.audit({entityName:"users",operation:"REGISTER_FAILED",summary:`Registration failed: email already exists (${email})`,ipAddress:auditIp,userAgent:auditUa,path:reqUrl.pathname,query:reqUrl.search});let verifGatesSignup=registerConfig.emailVerification?.enabled&&getEmailService?.()?.isAvailable();if(config.authentication?.preventUserEnumeration&&verifGatesSignup)return{success:!0,message:"Registration successful. Please check your email to verify your account."};return ctx.set.status=409,{success:!1,message:"Email already registered"}}let hashedPassword=await hashPassword(password4),domainExempt=isEmailExempt(email,config.authentication?.emailExemptDomains),emailService=getEmailService?.()??null,emailVerificationEnabled=!domainExempt&®isterConfig.emailVerification?.enabled&&emailService?.isAvailable(),verificationToken=emailVerificationEnabled?generateVerificationToken():null,tokenExpiresIn=registerConfig.emailVerification?.tokenExpiresIn||"24h",tokenExpiresAt=emailVerificationEnabled?new Date(Date.now()+parseTimeToMs(tokenExpiresIn)):null,insertValues={email,password:hashedPassword};if(emailVerificationEnabled&&verificationToken)insertValues.emailVerificationToken=hashVerificationToken(verificationToken),insertValues.emailVerificationTokenExpiresAt=tokenExpiresAt,insertValues.emailVerificationSentAt=new Date,insertValues.emailVerificationAttempts=1;let newUser=(await db.insert(usersTable).values(insertValues).returning())[0],registerDefaultRoles=resolveDefaultRoleNames(config.authentication);if(registerDefaultRoles.length>0)await assignDefaultRoles({db,userId:newUser.id,roleNames:registerDefaultRoles,rolesTable:resolved.rolesTable??config.rolesTable??null,userRolesTable:resolved.userRolesTable??config.userRolesTable??null,logger:logger2});let wantsProfile=registerConfig.createProfileOnRegister||createProfile,profilesTable=resolved.schemaTables?.profiles;if(wantsProfile&&profilesTable&&(firstName||lastName))try{let profileNow=new Date;await db.insert(profilesTable).values({userId:newUser.id,firstName:firstName??"",lastName:lastName??"",createdAt:profileNow,updatedAt:profileNow})}catch(err){log4.warn("Failed to create profile on register \u2014 continuing",{userId:newUser.id,error:err instanceof Error?err.message:String(err)})}if(log4.info("Registration successful",{userId:newUser.id,email,emailVerificationEnabled}),logger2.audit({entityName:"users",entityId:newUser.id,operation:"REGISTER",userId:newUser.id,summary:`New user registered: ${email}`,ipAddress:auditIp,userAgent:auditUa,path:reqUrl.pathname,query:reqUrl.search}),emailVerificationEnabled&&emailService&&verificationToken){let verificationLink=buildEmailActionLink({request:ctx.request,configuredUrl:registerConfig.emailVerification?.redirectUrl,path:"/verify-email",query:{token:verificationToken},allowedOrigins:config.authentication?.trustedAppOrigins});emailService.sendVerificationEmail(email,email.split("@")[0]||"User",verificationLink,appName||"Nucleus",config.authentication?.emailVerificationTemplates?.verification?.subject).then((result2)=>{if(result2.success)log4.info("Verification email sent",{email});else log4.error("Failed to send verification email",{email,error:result2.error})}).catch((err)=>{log4.error("Failed to send verification email",{email,error:err})});let resendCooldown=registerConfig.emailVerification?.resendCooldown||"60s",cooldownSeconds=parseTimeToMs(resendCooldown)/1000,maxResendAttempts=registerConfig.emailVerification?.maxResendAttempts||3;if(config.authentication?.preventUserEnumeration)return{success:!0,message:"Registration successful. Please check your email to verify your account."};return{success:!0,message:"Registration successful. Please check your email to verify your account.",data:{user:{id:newUser.id,email:newUser.email},emailVerificationRequired:!0,verification:{cooldownSeconds,canResendAt:new Date(Date.now()+cooldownSeconds*1000).toISOString(),attemptsRemaining:maxResendAttempts-1,maxAttempts:maxResendAttempts}}}}if(sendWelcomeEmail)sendWelcomeEmail(email,firstName||email.split("@")[0]||"User").catch((err)=>{log4.error("Failed to send welcome email",{email,error:err})});if(signAccessToken&&signRefreshToken&&createSession){let ipAddress=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent=ctx.request.headers.get("user-agent")||"",sessionParams={userId:newUser.id,deviceInfo:ensureDeviceInfo({ipAddress,userAgent},deviceContextFromRequest(ctx.request).clientHints),loginMethod:"register",rememberMe:!0},sessionId=await createSession(sessionParams),accessToken=signAccessToken(newUser.id,void 0,void 0,ctx.request.headers.get("x-tenant-schema")??void 0,void 0,sessionId),refreshToken=signRefreshToken(newUser.id,void 0,sessionId),deviceTokenCookie;if(saveSessionToDb){let reqSchemaName=ctx.request.headers.get("x-tenant-schema")||void 0,dtCfg=config.authentication?.deviceTrust;if(dtCfg?.enabled)sessionParams.deviceToken=readDeviceTokenFromCookieHeader(ctx.request.headers.get("cookie"),dtCfg);deviceTokenCookie=(await saveSessionToDb(sessionId,sessionParams,reqSchemaName))?.deviceTokenCookie}let tokenConfig={accessToken:{setHeadersEnabled:tokenResponseConfig?.accessToken?.setHeadersEnabled??!0,returnJson:tokenResponseConfig?.accessToken?.returnJson??!0},refreshToken:{setHeadersEnabled:tokenResponseConfig?.refreshToken?.setHeadersEnabled??!0,returnJson:tokenResponseConfig?.refreshToken?.returnJson??!0},sessionToken:{setHeadersEnabled:tokenResponseConfig?.sessionToken?.setHeadersEnabled??!0,returnJson:tokenResponseConfig?.sessionToken?.returnJson??!0}},securePart=cookies.secure?"; Secure":"",domainPart=cookies.domain?`; Domain=${cookies.domain}`:"",cookieOptions=`; Path=${cookies.path}; HttpOnly; SameSite=${cookies.sameSite}${securePart}${domainPart}`,cookiesToSet=[];if(tokenConfig.accessToken.setHeadersEnabled)cookiesToSet.push(`${cookies.accessTokenName}=${accessToken}${cookieOptions}; Max-Age=${cookies.accessTokenMaxAge}`);if(tokenConfig.refreshToken.setHeadersEnabled)cookiesToSet.push(`${cookies.refreshTokenName}=${refreshToken}${cookieOptions}; Max-Age=${cookies.refreshTokenMaxAge}`);if(tokenConfig.sessionToken.setHeadersEnabled)cookiesToSet.push(`${cookies.sessionTokenName}=${sessionId}${cookieOptions}; Max-Age=${cookies.sessionTokenMaxAge}`);if(deviceTokenCookie)cookiesToSet.push(deviceTokenCookie);let responseData={user:{id:newUser.id,email:newUser.email}};if(tokenConfig.accessToken.returnJson)responseData.accessToken=accessToken;if(tokenConfig.refreshToken.returnJson)responseData.refreshToken=refreshToken;if(tokenConfig.sessionToken.returnJson)responseData.sessionId=sessionId;let jsonBody=JSON.stringify(withEnvelopeFlags({success:!0,data:responseData})),headers=new Headers;headers.set("Content-Type","application/json"),headers.set("x-session-id",sessionId);for(let cookie of cookiesToSet)headers.append("Set-Cookie",cookie);return new Response(jsonBody,{status:200,headers})}return{success:!0,data:{user:{id:newUser.id,email:newUser.email}}}}});return collectRoutes([{prefix:route,routes:[routePostRoute]}])}var init_register=__esm(()=>{init_DeviceTrust();init_scopes();init_response();init_routeCollector();init_assignDefaultRole();init_deviceInfo();init_types19();init_utils6();init_types19()});var SessionResponseSchema,SessionListResponseSchema,RevokeSessionBodySchema,RevokeAllSessionsBodySchema,SessionActivityResponseSchema,AdminRevokeSessionsBodySchema;var init_types20=__esm(()=>{init_esm3();SessionResponseSchema=Type.Object({id:Type.String(),deviceName:Type.Optional(Type.String()),deviceType:Type.Optional(Type.String()),browserName:Type.Optional(Type.String()),browserVersion:Type.Optional(Type.String()),osName:Type.Optional(Type.String()),osVersion:Type.Optional(Type.String()),ipAddress:Type.String(),locationCountry:Type.Optional(Type.String()),locationCity:Type.Optional(Type.String()),lastActivityAt:Type.String(),createdAt:Type.String(),isCurrent:Type.Boolean(),loginMethod:Type.Optional(Type.String()),trustScore:Type.Optional(Type.Number())}),SessionListResponseSchema=Type.Object({success:Type.Boolean(),data:Type.Optional(Type.Object({sessions:Type.Array(SessionResponseSchema),currentSessionId:Type.Optional(Type.String()),totalCount:Type.Number()})),message:Type.Optional(Type.String())}),RevokeSessionBodySchema=Type.Object({reason:Type.Optional(Type.String())}),RevokeAllSessionsBodySchema=Type.Object({excludeCurrent:Type.Optional(Type.Boolean()),reason:Type.Optional(Type.String())}),SessionActivityResponseSchema=Type.Object({success:Type.Boolean(),data:Type.Optional(Type.Object({recentActivity:Type.Array(Type.Object({sessionId:Type.String(),action:Type.String(),ipAddress:Type.String(),timestamp:Type.String(),deviceInfo:Type.Optional(Type.String())}))})),message:Type.Optional(Type.String())}),AdminRevokeSessionsBodySchema=Type.Optional(Type.Object({sessionId:Type.Optional(Type.String()),reason:Type.Optional(Type.String())}))});function formatSessionForResponse(session){let get=(snake,camel3)=>session[snake]??session[camel3],getDate=(snake,camel3)=>{let val=session[snake]??session[camel3];if(!val)return;return val instanceof Date?val.toISOString():String(val)};return{id:session.id,deviceName:get("device_name","deviceName"),deviceType:get("device_type","deviceType"),deviceFingerprint:get("device_fingerprint","deviceFingerprint"),browserName:get("browser_name","browserName"),browserVersion:get("browser_version","browserVersion"),osName:get("os_name","osName"),osVersion:get("os_version","osVersion"),ipAddress:get("ip_address","ipAddress"),locationCountry:get("location_country","locationCountry"),locationCity:get("location_city","locationCity"),lastActivityAt:getDate("last_activity_at","lastActivityAt"),createdAt:getDate("created_at","createdAt"),isCurrent:get("is_current","isCurrent"),loginMethod:get("login_method","loginMethod"),trustScore:get("trust_score","trustScore")}}var init_utils11=()=>{};import{and as and27,desc as desc6,eq as eq63,isNull as isNull5}from"drizzle-orm";function createSessionsRoute(config,sessionsConfig,sessionsTable){let{db,logger:logger2}=config,log4=logger2.scoped(AUTH_SESSION),baseRoute=sessionsConfig.route||"/auth/sessions";if(!sessionsConfig.enabled||!sessionsTable)return collectRoutes();let tableColumns=sessionsTable,_col=(name2)=>{let snakeCase=name2.replace(/([A-Z])/g,"_$1").toLowerCase();return tableColumns[name2]||tableColumns[snakeCase]},getSessionsForRequest=(request)=>{let resolved=resolveAuthTablesForRequest(request,config),reqTable=resolved.sessionsTable||sessionsTable,reqCols=reqTable,reqCol=(name2)=>{let snakeCase=name2.replace(/([A-Z])/g,"_$1").toLowerCase();return reqCols[name2]||reqCols[snakeCase]},trustedDevicesTable=resolved.schemaTables?.trustedDevices??resolved.schemaTables?.trusted_devices;return{sessionsTable:reqTable,col:reqCol,trustedDevicesTable}},routeGetRoot=defineRoute({method:"GET",path:"/",detail:{tags:["Authentication"],summary:"List active sessions",description:"Get all active sessions for the current user"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let currentSessionId=ctx.request.headers.get("x-session-id"),sessions=await db.select().from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0),isNull5(col15("revokedAt")))).orderBy(desc6(col15("lastActivityAt"))),realSessions=sessions.filter((s)=>{let sess=s,fp=(sess.deviceFingerprint||"").toLowerCase(),ip=sess.ipAddress||"";return!((!fp||fp==="--"||fp==="--unknown"||fp.includes("bot/crawler")||fp.includes("headless")||fp.includes("unknown-unknown"))&&(ip==="127.0.0.1"||ip==="::1"||ip==="localhost"||!ip))}),formattedSessions=realSessions.map((s)=>{let session=s,formatted=formatSessionForResponse(session);return formatted.isCurrent=session.id===currentSessionId,formatted});return log4.info("Sessions list retrieved",{userId,totalInDb:sessions.length,filteredCount:realSessions.length,hiddenBotSessions:sessions.length-realSessions.length}),{success:!0,data:{sessions:formattedSessions,currentSessionId,totalCount:realSessions.length}}}}),routeGetCurrent=defineRoute({method:"GET",path:"/current",detail:{tags:["Authentication"],summary:"Get current session",description:"Get details of the current session"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id"),sessionId=ctx.request.headers.get("x-session-id");if(!userId||!sessionId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let sessions=await db.select().from(sessionsTable2).where(eq63(col15("id"),sessionId)).limit(1);if(sessions.length===0)return ctx.set.status=404,{success:!1,message:"Session not found"};let session=sessions[0],formatted=formatSessionForResponse(session);return formatted.isCurrent=!0,{success:!0,data:formatted}}}),routeDeleteSessionid=defineRoute({method:"DELETE",path:"/:sessionId",body:RevokeSessionBodySchema,detail:{tags:["Authentication"],summary:"Revoke session",description:"Revoke a specific session by ID"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{sessionId}=ctx.params,body=ctx.body,currentSessionId=ctx.request.headers.get("x-session-id");if((await db.select().from(sessionsTable2).where(and27(eq63(col15("id"),sessionId),eq63(col15("userId"),userId))).limit(1)).length===0)return ctx.set.status=404,{success:!1,message:"Session not found"};let isCurrentSession=sessionId===currentSessionId;await db.update(sessionsTable2).set({isActive:!1,revokedAt:new Date,revokedReason:isCurrentSession?"user_logout":body.reason||"user_revoked"}).where(eq63(col15("id"),sessionId)),await forgetSessionsInRedis([sessionId]),log4.info("Session revoked",{userId,sessionId,isCurrentSession,reason:body.reason||"user_revoked"});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"user_sessions",entityId:sessionId,operation:isCurrentSession?"LOGOUT":"SESSION_REVOKE",userId:userId||void 0,summary:isCurrentSession?"User logged out via session revoke":`Session revoked (${sessionId.substring(0,8)}...)`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:isCurrentSession?"Logged out successfully":"Session revoked successfully"}}}),routeDeleteAll=defineRoute({method:"DELETE",path:"/all",body:RevokeAllSessionsBodySchema,detail:{tags:["Authentication"],summary:"Revoke all sessions",description:"Revoke all sessions for the current user (optionally exclude current)"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let body=ctx.body,currentSessionId=ctx.request.headers.get("x-session-id"),query=db.update(sessionsTable2).set({isActive:!1,revokedAt:new Date,revokedReason:body.reason||"user_revoked"}).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0)));if(body.excludeCurrent&¤tSessionId){let{ne:ne4}=await import("drizzle-orm");query=db.update(sessionsTable2).set({isActive:!1,revokedAt:new Date,revokedReason:body.reason||"user_revoked"}).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0),ne4(col15("id"),currentSessionId)))}let revoked=await query.returning({id:col15("id")});await forgetSessionsInRedis(revoked.map((r)=>r.id)),log4.info("All sessions revoked",{userId,excludeCurrent:body.excludeCurrent,reason:body.reason||"user_revoked"});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"user_sessions",operation:"SESSION_REVOKE_ALL",userId:userId||void 0,summary:body.excludeCurrent?"All other sessions revoked":"All sessions revoked",ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:body.excludeCurrent?"All other sessions revoked successfully":"All sessions revoked successfully"}}}),routeGetStats=defineRoute({method:"GET",path:"/stats",detail:{tags:["Authentication"],summary:"Session statistics",description:"Get session statistics for the current user"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{count:count3,countDistinct}=await import("drizzle-orm"),activeSessions=await db.select({count:count3()}).from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0),isNull5(col15("revokedAt")))),uniqueDevices=await db.select({count:countDistinct(col15("deviceFingerprint"))}).from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0))),uniqueIps=await db.select({count:countDistinct(col15("ipAddress"))}).from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0)));return{success:!0,data:{activeSessions:activeSessions[0]?.count||0,uniqueDevices:uniqueDevices[0]?.count||0,uniqueIpAddresses:uniqueIps[0]?.count||0}}}}),APPROVAL_TOKEN_TTL_MS=86400000,buildResultHtml=(action,success,message)=>{let icon=success?action==="approve"?"\u2705":"\uD83D\uDEAB":"\u274C",title=success?action==="approve"?"Device Approved":"Device Rejected":"Action Failed",bName=sessionsConfig.brandName||"Nucleus";return`<!DOCTYPE html>
|
|
453
453
|
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
454
454
|
<title>${title} \u2014 ${bName}</title>
|
|
455
455
|
<style>*{box-sizing:border-box}body{margin:0;padding:0;background-color:#f4f4f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;}</style>
|
|
@@ -469,7 +469,7 @@ ${strMDSAlgs}`)}if(attestationStatementAlg!==void 0&&authenticatorGetInfo?.algor
|
|
|
469
469
|
</table>
|
|
470
470
|
</td></tr>
|
|
471
471
|
</table>
|
|
472
|
-
</body></html>`},extractToken=(ctx)=>{let queryToken=new URL(ctx.request.url).searchParams.get("token");if(queryToken){let isForm=(ctx.request.headers.get("content-type")||"").includes("application/x-www-form-urlencoded");return{token:queryToken,isFormSubmission:isForm}}return{token:ctx.body?.token||null,isFormSubmission:!1}},routePostApprove=defineRoute({method:"POST",path:"/approve",detail:{tags:["Authentication"],summary:"Approve pending device",description:"Approve a pending device login request"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{token,isFormSubmission}=extractToken(ctx);if(!token){if(isFormSubmission)return new Response(buildResultHtml("approve",!1,"Token is required"),{status:400,headers:{"Content-Type":"text/html; charset=utf-8"}});return ctx.set.status=400,{success:!1,message:"Token is required"}}let sessions=await db.select().from(sessionsTable2).where(eq63(col15("approvalToken"),token)).limit(1);if(sessions.length===0){if(isFormSubmission)return new Response(buildResultHtml("approve",!1,"This approval link is invalid or has already been used."),{status:404,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:"Invalid or expired approval token"}}let session=sessions[0];if(session.approvalStatus!=="pending"){if(isFormSubmission)return new Response(buildResultHtml("approve",!0,"This device has already been processed."),{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:"Session already processed"}}let requestedAt=session.approvalRequestedAt||session.approval_requested_at;if(requestedAt){let requestedTime=new Date(requestedAt).getTime();if(Date.now()-requestedTime>APPROVAL_TOKEN_TTL_MS){await db.update(sessionsTable2).set({approvalStatus:"rejected",isActive:!1,revokedAt:new Date,revokedReason:"approval_token_expired",approvalRespondedAt:new Date,approvalToken:null}).where(eq63(col15("id"),session.id)),log4.info("Approval token expired",{sessionId:session.id});let msg="This approval link has expired (24h limit). Please log in again.";if(isFormSubmission)return new Response(buildResultHtml("approve",!1,msg),{status:410,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:msg}}}await db.update(sessionsTable2).set({approvalStatus:"approved",isActive:!0,approvalRespondedAt:new Date,approvalToken:null}).where(eq63(col15("id"),session.id));try{let dtTable=config.authentication?.deviceTrust?.enabled?getSessionsForRequest(ctx.request).trustedDevicesTable:void 0;if(dtTable&&db){let{activateDeviceForSession:activateDeviceForSession2}=await Promise.resolve().then(() => (init_store3(),exports_store));await activateDeviceForSession2(db,dtTable,session.id)}}catch(dtErr){log4.warn("[AUTH] device-trust activation on approve failed",{sessionId:session.id,error:dtErr instanceof Error?dtErr.message:String(dtErr)})}if(log4.info("Device approved",{sessionId:session.id,userId:session.userId}),isFormSubmission)return new Response(buildResultHtml("approve",!0,"The device has been approved and can now access the account."),{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!0,message:"Device approved successfully"}}}),routePostReject=defineRoute({method:"POST",path:"/reject",detail:{tags:["Authentication"],summary:"Reject pending device",description:"Reject a pending device login request"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{token,isFormSubmission}=extractToken(ctx);if(!token){if(isFormSubmission)return new Response(buildResultHtml("reject",!1,"Token is required"),{status:400,headers:{"Content-Type":"text/html; charset=utf-8"}});return ctx.set.status=400,{success:!1,message:"Token is required"}}let sessions=await db.select().from(sessionsTable2).where(eq63(col15("approvalToken"),token)).limit(1);if(sessions.length===0){if(isFormSubmission)return new Response(buildResultHtml("reject",!1,"This approval link is invalid or has already been used."),{status:404,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:"Invalid or expired approval token"}}let session=sessions[0];if(session.approvalStatus!=="pending"){if(isFormSubmission)return new Response(buildResultHtml("reject",!0,"This device has already been processed."),{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:"Session already processed"}}let requestedAt=session.approvalRequestedAt||session.approval_requested_at,isExpired=requestedAt?Date.now()-new Date(requestedAt).getTime()>APPROVAL_TOKEN_TTL_MS:!1;await db.update(sessionsTable2).set({approvalStatus:"rejected",isActive:!1,revokedAt:new Date,revokedReason:isExpired?"approval_token_expired":"user_rejected",approvalRespondedAt:new Date,approvalToken:null}).where(eq63(col15("id"),session.id));try{let dtTable=config.authentication?.deviceTrust?.enabled?getSessionsForRequest(ctx.request).trustedDevicesTable:void 0;if(dtTable&&db){let{rejectDeviceForSession:rejectDeviceForSession2}=await Promise.resolve().then(() => (init_store3(),exports_store));await rejectDeviceForSession2(db,dtTable,session.id)}}catch{}log4.info("Device rejected",{sessionId:session.id,userId:session.userId,isExpired});let message=isExpired?"Approval link has expired. The session was automatically rejected.":"Device rejected and blocked. The login attempt has been denied.";if(isFormSubmission)return new Response(buildResultHtml("reject",!0,message),{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!0,message}}}),routeGetPending=defineRoute({method:"GET",path:"/pending",detail:{tags:["Authentication"],summary:"List pending devices",description:"Get all pending device approval requests for the current user"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let sessions=await db.select().from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("approvalStatus"),"pending"))).orderBy(desc6(col15("createdAt")));return{success:!0,data:{sessions:sessions.map((s)=>{let session=s;return{...formatSessionForResponse(session),approvalStatus:session.approval_status||session.approvalStatus,approvalToken:session.approval_token||session.approvalToken,approvalRequestedAt:session.approval_requested_at?.toISOString()||session.approvalRequestedAt?.toISOString()}}),totalCount:sessions.length}}}}),brandName=sessionsConfig.brandName||"Nucleus",buildApprovalPageHtml=(session,action,token,status)=>{let isApprove=action==="approve",accentColor=isApprove?"#16a34a":"#dc2626",actionLabel=isApprove?"Approve Device":"Reject & Block",icon=isApprove?"\u2713":"\u2717",bodyContent;if(status==="invalid")bodyContent=`
|
|
472
|
+
</body></html>`},extractToken=(ctx)=>{let queryToken=new URL(ctx.request.url).searchParams.get("token");if(queryToken){let isForm=(ctx.request.headers.get("content-type")||"").includes("application/x-www-form-urlencoded");return{token:queryToken,isFormSubmission:isForm}}return{token:ctx.body?.token||null,isFormSubmission:!1}},routePostApprove=defineRoute({method:"POST",path:"/approve",detail:{tags:["Authentication"],summary:"Approve pending device",description:"Approve a pending device login request"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{token,isFormSubmission}=extractToken(ctx);if(!token){if(isFormSubmission)return new Response(buildResultHtml("approve",!1,"Token is required"),{status:400,headers:{"Content-Type":"text/html; charset=utf-8"}});return ctx.set.status=400,{success:!1,message:"Token is required"}}let sessions=await db.select().from(sessionsTable2).where(eq63(col15("approvalToken"),token)).limit(1);if(sessions.length===0){if(isFormSubmission)return new Response(buildResultHtml("approve",!1,"This approval link is invalid or has already been used."),{status:404,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:"Invalid or expired approval token"}}let session=sessions[0];if(session.approvalStatus!=="pending"){if(isFormSubmission)return new Response(buildResultHtml("approve",!0,"This device has already been processed."),{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:"Session already processed"}}let requestedAt=session.approvalRequestedAt||session.approval_requested_at;if(requestedAt){let requestedTime=new Date(requestedAt).getTime();if(Date.now()-requestedTime>APPROVAL_TOKEN_TTL_MS){await db.update(sessionsTable2).set({approvalStatus:"rejected",isActive:!1,revokedAt:new Date,revokedReason:"approval_token_expired",approvalRespondedAt:new Date,approvalToken:null}).where(eq63(col15("id"),session.id)),await forgetSessionsInRedis([session.id]),log4.info("Approval token expired",{sessionId:session.id});let msg="This approval link has expired (24h limit). Please log in again.";if(isFormSubmission)return new Response(buildResultHtml("approve",!1,msg),{status:410,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:msg}}}await db.update(sessionsTable2).set({approvalStatus:"approved",isActive:!0,approvalRespondedAt:new Date,approvalToken:null}).where(eq63(col15("id"),session.id));try{let dtTable=config.authentication?.deviceTrust?.enabled?getSessionsForRequest(ctx.request).trustedDevicesTable:void 0;if(dtTable&&db){let{activateDeviceForSession:activateDeviceForSession2}=await Promise.resolve().then(() => (init_store3(),exports_store));await activateDeviceForSession2(db,dtTable,session.id)}}catch(dtErr){log4.warn("[AUTH] device-trust activation on approve failed",{sessionId:session.id,error:dtErr instanceof Error?dtErr.message:String(dtErr)})}if(log4.info("Device approved",{sessionId:session.id,userId:session.userId}),isFormSubmission)return new Response(buildResultHtml("approve",!0,"The device has been approved and can now access the account."),{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!0,message:"Device approved successfully"}}}),routePostReject=defineRoute({method:"POST",path:"/reject",detail:{tags:["Authentication"],summary:"Reject pending device",description:"Reject a pending device login request"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{token,isFormSubmission}=extractToken(ctx);if(!token){if(isFormSubmission)return new Response(buildResultHtml("reject",!1,"Token is required"),{status:400,headers:{"Content-Type":"text/html; charset=utf-8"}});return ctx.set.status=400,{success:!1,message:"Token is required"}}let sessions=await db.select().from(sessionsTable2).where(eq63(col15("approvalToken"),token)).limit(1);if(sessions.length===0){if(isFormSubmission)return new Response(buildResultHtml("reject",!1,"This approval link is invalid or has already been used."),{status:404,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:"Invalid or expired approval token"}}let session=sessions[0];if(session.approvalStatus!=="pending"){if(isFormSubmission)return new Response(buildResultHtml("reject",!0,"This device has already been processed."),{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!1,message:"Session already processed"}}let requestedAt=session.approvalRequestedAt||session.approval_requested_at,isExpired=requestedAt?Date.now()-new Date(requestedAt).getTime()>APPROVAL_TOKEN_TTL_MS:!1;await db.update(sessionsTable2).set({approvalStatus:"rejected",isActive:!1,revokedAt:new Date,revokedReason:isExpired?"approval_token_expired":"user_rejected",approvalRespondedAt:new Date,approvalToken:null}).where(eq63(col15("id"),session.id));try{let dtTable=config.authentication?.deviceTrust?.enabled?getSessionsForRequest(ctx.request).trustedDevicesTable:void 0;if(dtTable&&db){let{rejectDeviceForSession:rejectDeviceForSession2}=await Promise.resolve().then(() => (init_store3(),exports_store));await rejectDeviceForSession2(db,dtTable,session.id)}}catch{}log4.info("Device rejected",{sessionId:session.id,userId:session.userId,isExpired});let message=isExpired?"Approval link has expired. The session was automatically rejected.":"Device rejected and blocked. The login attempt has been denied.";if(isFormSubmission)return new Response(buildResultHtml("reject",!0,message),{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}});return{success:!0,message}}}),routeGetPending=defineRoute({method:"GET",path:"/pending",detail:{tags:["Authentication"],summary:"List pending devices",description:"Get all pending device approval requests for the current user"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let sessions=await db.select().from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("approvalStatus"),"pending"))).orderBy(desc6(col15("createdAt")));return{success:!0,data:{sessions:sessions.map((s)=>{let session=s;return{...formatSessionForResponse(session),approvalStatus:session.approval_status||session.approvalStatus,approvalToken:session.approval_token||session.approvalToken,approvalRequestedAt:session.approval_requested_at?.toISOString()||session.approvalRequestedAt?.toISOString()}}),totalCount:sessions.length}}}}),brandName=sessionsConfig.brandName||"Nucleus",buildApprovalPageHtml=(session,action,token,status)=>{let isApprove=action==="approve",accentColor=isApprove?"#16a34a":"#dc2626",actionLabel=isApprove?"Approve Device":"Reject & Block",icon=isApprove?"\u2713":"\u2717",bodyContent;if(status==="invalid")bodyContent=`
|
|
473
473
|
<div style="text-align:center;padding:40px 20px;">
|
|
474
474
|
<div style="font-size:48px;margin-bottom:16px;">\u26A0\uFE0F</div>
|
|
475
475
|
<h2 style="margin:0 0 8px;color:#111827;font-size:20px;">Invalid Token</h2>
|
|
@@ -522,7 +522,7 @@ ${strMDSAlgs}`)}if(attestationStatementAlg!==void 0&&authenticatorGetInfo?.algor
|
|
|
522
522
|
</table>
|
|
523
523
|
</td></tr>
|
|
524
524
|
</table>
|
|
525
|
-
</body></html>`},routeGetApprovePage=defineRoute({method:"GET",path:"/approve-page",detail:{tags:["Authentication"],summary:"Approval page",description:"Standalone HTML page for approving a device (no frontend auth required)"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return new Response("Service unavailable",{status:503});let token=new URL(ctx.request.url).searchParams.get("token");if(!token){let html2=buildApprovalPageHtml({},"approve","","invalid");return new Response(html2,{status:400,headers:{"Content-Type":"text/html; charset=utf-8"}})}let sessions=await db.select().from(sessionsTable2).where(eq63(col15("approvalToken"),token)).limit(1);if(sessions.length===0){let html2=buildApprovalPageHtml({},"approve",token,"invalid");return new Response(html2,{status:404,headers:{"Content-Type":"text/html; charset=utf-8"}})}let session=sessions[0];if(session.approvalStatus!=="pending"&&session.approval_status!=="pending"){let html2=buildApprovalPageHtml(session,"approve",token,"already_processed");return new Response(html2,{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}})}let requestedAt=session.approvalRequestedAt||session.approval_requested_at;if(requestedAt&&Date.now()-new Date(requestedAt).getTime()>APPROVAL_TOKEN_TTL_MS){let html2=buildApprovalPageHtml(session,"approve",token,"expired");return new Response(html2,{status:410,headers:{"Content-Type":"text/html; charset=utf-8"}})}let html=buildApprovalPageHtml(session,"approve",token,"pending");return new Response(html,{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}})}}),routeGetRejectPage=defineRoute({method:"GET",path:"/reject-page",detail:{tags:["Authentication"],summary:"Rejection page",description:"Standalone HTML page for rejecting a device (no frontend auth required)"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return new Response("Service unavailable",{status:503});let token=new URL(ctx.request.url).searchParams.get("token");if(!token){let html2=buildApprovalPageHtml({},"reject","","invalid");return new Response(html2,{status:400,headers:{"Content-Type":"text/html; charset=utf-8"}})}let sessions=await db.select().from(sessionsTable2).where(eq63(col15("approvalToken"),token)).limit(1);if(sessions.length===0){let html2=buildApprovalPageHtml({},"reject",token,"invalid");return new Response(html2,{status:404,headers:{"Content-Type":"text/html; charset=utf-8"}})}let session=sessions[0];if(session.approvalStatus!=="pending"&&session.approval_status!=="pending"){let html2=buildApprovalPageHtml(session,"reject",token,"already_processed");return new Response(html2,{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}})}let requestedAt=session.approvalRequestedAt||session.approval_requested_at;if(requestedAt&&Date.now()-new Date(requestedAt).getTime()>APPROVAL_TOKEN_TTL_MS){let html2=buildApprovalPageHtml(session,"reject",token,"expired");return new Response(html2,{status:410,headers:{"Content-Type":"text/html; charset=utf-8"}})}let html=buildApprovalPageHtml(session,"reject",token,"pending");return new Response(html,{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}})}}),routeGetApprovalStatus=defineRoute({method:"GET",path:"/approval-status",detail:{tags:["Authentication"],summary:"Check approval status",description:"Check the approval status of a pending session"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let sessionId=new URL(ctx.request.url).searchParams.get("sessionId");if(!sessionId)return ctx.set.status=400,{success:!1,message:"sessionId is required"};let sessions=await db.select().from(sessionsTable2).where(eq63(col15("id"),sessionId)).limit(1);if(sessions.length===0)return ctx.set.status=404,{success:!1,message:"Session not found"};let session=sessions[0];return{success:!0,data:{approvalStatus:session.approvalStatus||session.approval_status||"unknown",isActive:session.isActive||session.is_active}}}}),routeGetDevices=defineRoute({method:"GET",path:"/devices",detail:{tags:["Authentication"],summary:"List remembered devices",description:"List the caller's remembered (device-trust) devices; never returns the token."},handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let dtTable=getSessionsForRequest(ctx.request).trustedDevicesTable;if(!dtTable||!db)return{success:!0,data:{items:[]}};let{listUserDevices:listUserDevices2}=await Promise.resolve().then(() => (init_store3(),exports_store));return{success:!0,data:{items:await listUserDevices2(db,dtTable,userId)}}}}),routeDeleteDevicesId=defineRoute({method:"DELETE",path:"/devices/:id",detail:{tags:["Authentication"],summary:"Revoke a remembered device",description:"Owner-scoped revoke of one remembered device (untrusts it)."},handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let id=ctx.params.id,dtTable=getSessionsForRequest(ctx.request).trustedDevicesTable;if(!dtTable||!db)return ctx.set.status=503,{success:!1,message:"Device trust not enabled"};let{revokeDeviceById:revokeDeviceById2}=await Promise.resolve().then(() => (init_store3(),exports_store));if(await revokeDeviceById2(db,dtTable,id,userId,"user_revoked")===0)return ctx.set.status=404,{success:!1,message:"Device not found"};return log4.info("Remembered device revoked",{userId,deviceId:id}),{success:!0,message:"Device revoked"}}}),adminGuard=createGodminGuard2({logger:logger2,db,schemaTables:config.schemaTables??{},area:"session management",allowedRoles:sessionsConfig.adminRoles??[]}),routeGetAdminUserid=defineRoute({method:"GET",path:"/admin/:userId",guards:[adminGuard],detail:{tags:["Authentication"],summary:"List another user's active sessions (admin)",description:"Godmin or a role named in authentication.sessions.adminRoles. Used for offboarding and lost-device response."},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{userId}=ctx.params,sessions=await db.select().from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0),isNull5(col15("revokedAt")))).orderBy(desc6(col15("lastActivityAt")));return{success:!0,data:{sessions:sessions.map((session)=>formatSessionForResponse(session)),totalCount:sessions.length}}}}),routeDeleteAdminUserid=defineRoute({method:"DELETE",path:"/admin/:userId",guards:[adminGuard],body:AdminRevokeSessionsBodySchema,detail:{tags:["Authentication"],summary:"End another user's sessions (admin)",description:"Ends every active session of the given user, or just one when `sessionId` is supplied. Godmin or authentication.sessions.adminRoles."},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{userId}=ctx.params,body=ctx.body??{},actorId=ctx.request.headers.get("x-user-id")||void 0,target2=body.sessionId?and27(eq63(col15("id"),body.sessionId),eq63(col15("userId"),userId),eq63(col15("isActive"),!0)):and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0)),affected=await db.update(sessionsTable2).set({isActive:!1,revokedAt:new Date,revokedReason:body.reason||"admin_revoked"}).where(target2).returning({id:col15("id")});log4.warn("Sessions revoked by an administrator",{actorId,subjectUserId:userId,sessionId:body.sessionId,revoked:affected.length,reason:body.reason||"admin_revoked"});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"user_sessions",entityId:body.sessionId,operation:"SESSION_REVOKE_ALL",userId:actorId,summary:body.sessionId?`Admin revoked one session of user ${userId}`:`Admin revoked ${affected.length} session(s) of user ${userId}`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:`${affected.length} session${affected.length===1?"":"s"} ended`,data:{revoked:affected.length}}}});return collectRoutes([{prefix:baseRoute,routes:[routeGetRoot,routeGetCurrent,routeDeleteSessionid,routeDeleteAll,routeGetStats,routePostApprove,routePostReject,routeGetPending,routeGetApprovePage,routeGetRejectPage,routeGetApprovalStatus,routeGetDevices,routeDeleteDevicesId,routeGetAdminUserid,routeDeleteAdminUserid]}])}var init_sessions=__esm(()=>{init_scopes();init_routeCollector();init_godminGuard();init_types20();init_utils11();init_types20()});function resolveCookies(cookieConfig){return{accessTokenName:cookieConfig?.accessTokenName||"access_token",refreshTokenName:cookieConfig?.refreshTokenName||"refresh_token",sessionTokenName:cookieConfig?.sessionTokenName||"session_token",accessTokenMaxAge:cookieConfig?.accessTokenMaxAge||900,refreshTokenMaxAge:cookieConfig?.refreshTokenMaxAge||604800,sessionTokenMaxAge:cookieConfig?.sessionTokenMaxAge||2592000,secure:cookieConfig?.secure??!0,httpOnly:cookieConfig?.httpOnly??!0,sameSite:cookieConfig?.sameSite||"lax",path:cookieConfig?.path||"/",domain:cookieConfig?.domain}}function buildCookieHeaders(cookies,tokens){let securePart=cookies.secure?"; Secure":"",domainPart=cookies.domain?`; Domain=${cookies.domain}`:"",cookieOptions=`; Path=${cookies.path}; HttpOnly; SameSite=${cookies.sameSite}${securePart}${domainPart}`,headers=new Headers;return headers.set("Content-Type","application/json"),headers.set("x-session-id",tokens.sessionId),headers.append("Set-Cookie",`${cookies.accessTokenName}=${tokens.accessToken}${cookieOptions}; Max-Age=${cookies.accessTokenMaxAge}`),headers.append("Set-Cookie",`${cookies.refreshTokenName}=${tokens.refreshToken}${cookieOptions}; Max-Age=${cookies.refreshTokenMaxAge}`),headers.append("Set-Cookie",`${cookies.sessionTokenName}=${tokens.sessionId}${cookieOptions}; Max-Age=${cookies.sessionTokenMaxAge}`),headers}var WebAuthnRegisterOptionsSchema,WebAuthnRegisterVerifySchema,WebAuthnAuthOptionsSchema,WebAuthnAuthVerifySchema,WebAuthnRenameSchema;var init_types21=__esm(()=>{init_esm3();WebAuthnRegisterOptionsSchema=Type.Object({nickname:Type.Optional(Type.String({maxLength:128}))}),WebAuthnRegisterVerifySchema=Type.Object({response:Type.Any(),challenge:Type.String(),nickname:Type.Optional(Type.String({maxLength:128}))}),WebAuthnAuthOptionsSchema=Type.Object({email:Type.Optional(Type.String({format:"email"}))}),WebAuthnAuthVerifySchema=Type.Object({response:Type.Any(),challenge:Type.String(),rememberMe:Type.Optional(Type.Boolean())}),WebAuthnRenameSchema=Type.Object({nickname:Type.String({minLength:1,maxLength:128})})});import{eq as eq64}from"drizzle-orm";function getSchema(ctx){return ctx.request.headers.get("x-tenant-schema")||void 0}function getUserId2(ctx){return ctx.request.headers.get("x-user-id")}function createWebAuthnRoute(config,routeOptions,webauthnService,helpers3,cookieConfig){let{db,logger:logger2}=config,basePath=routeOptions.basePath||"/auth/webauthn",cookies=resolveCookies(cookieConfig);if(!routeOptions.enabled)return collectRoutes();let routePostRegisterOptions=defineRoute({method:"POST",path:"/register/options",body:WebAuthnRegisterOptionsSchema,handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let user=(await db.select().from(usersTable).where(eq64(usersTable.id,userId)).limit(1))[0];if(!user)return ctx.set.status=404,{success:!1,message:"User not found"};return{success:!0,data:await webauthnService.createRegistrationOptions({userId,userName:user.email||userId,userDisplayName:user.email||userId,schemaName:getSchema(ctx)})}}}),routePostRegisterVerify=defineRoute({method:"POST",path:"/register/verify",body:WebAuthnRegisterVerifySchema,handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let body=ctx.body,credential=await webauthnService.verifyRegistration({response:body.response,expectedChallenge:body.challenge,userId,nickname:body.nickname,schemaName:getSchema(ctx)});if(!credential)return logger2.warn("[WEBAUTHN] Registration verification failed",{userId}),ctx.set.status=400,{success:!1,message:"Registration failed"};return{success:!0,data:{id:credential.id,credentialId:credential.credentialId,nickname:credential.nickname,deviceType:credential.deviceType,backedUp:credential.backedUp,authenticatorAttachment:credential.authenticatorAttachment,aaguid:credential.aaguid,transports:credential.transports,lastUsedAt:credential.lastUsedAt,revokedAt:credential.revokedAt,createdAt:credential.createdAt}}}}),routePostAuthenticateOptions=defineRoute({method:"POST",path:"/authenticate/options",body:WebAuthnAuthOptionsSchema,handler:async(ctx)=>{let body=ctx.body,resolvedUserId;if(body.email){let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(db&&usersTable){let user=(await db.select().from(usersTable).where(eq64(usersTable.email,body.email.toLowerCase())).limit(1))[0];if(user)resolvedUserId=user.id}}return{success:!0,data:await webauthnService.createAuthenticationOptions({userId:resolvedUserId,schemaName:getSchema(ctx)})}}}),routePostAuthenticateVerify=defineRoute({method:"POST",path:"/authenticate/verify",body:WebAuthnAuthVerifySchema,handler:async(ctx)=>{let body=ctx.body,result=await webauthnService.verifyAuthentication({response:body.response,expectedChallenge:body.challenge,schemaName:getSchema(ctx)});if(!result.verified||!result.userId)return ctx.set.status=401,{success:!1,message:"Authentication failed"};let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let user=(await db.select().from(usersTable).where(eq64(usersTable.id,result.userId)).limit(1))[0];if(!user)return ctx.set.status=401,{success:!1,message:"User not found"};let webauthnState=evaluateAccountState(user);if(!webauthnState.allowed)return ctx.set.status=401,{success:!1,message:webauthnState.message};let roles=[],claims=[],claimScopes={};try{let resolved=resolveAuthTablesForRequest(ctx.request,config),rc=await fetchUserRolesAndClaims(db,result.userId,resolved);roles=rc.roles,claims=rc.claims,claimScopes=rc.claimScopes}catch{}let ipAddress=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent=ctx.request.headers.get("user-agent")||"",sessionParams={userId:result.userId,deviceInfo:ensureDeviceInfo({ipAddress,userAgent},deviceContextFromRequest(ctx.request).clientHints),loginMethod:"webauthn",rememberMe:body.rememberMe??!1},sessionId=await helpers3.createSession(sessionParams),accessToken=helpers3.signAccessToken(result.userId,roles.length>0?roles:void 0,claims.length>0?claims:void 0,getSchema(ctx),claimScopes,sessionId),refreshToken=helpers3.signRefreshToken(result.userId,body.rememberMe??!1,sessionId),deviceTokenCookie;if(helpers3.saveSessionToDb){let dtCfg=config.authentication?.deviceTrust;if(dtCfg?.enabled)sessionParams.deviceToken=readDeviceTokenFromCookieHeader(ctx.request.headers.get("cookie"),dtCfg);let saveResult=await helpers3.saveSessionToDb(sessionId,sessionParams,getSchema(ctx));if(saveResult?.denied)return ctx.set.status=403,{success:!1,message:"This device could not be recognized. Please contact support."};if(deviceTokenCookie=saveResult?.deviceTokenCookie,saveResult?.requiresApproval){if(deviceTokenCookie)ctx.set.headers["Set-Cookie"]=deviceTokenCookie;return ctx.set.status=202,{success:!1,requiresApproval:!0,sessionId:saveResult.sessionId??sessionId,message:"Login requires approval"}}}let headers=buildCookieHeaders(cookies,{accessToken,refreshToken,sessionId});if(deviceTokenCookie)headers.append("Set-Cookie",deviceTokenCookie);return logger2.info("[WEBAUTHN] Authentication successful",{userId:result.userId,credentialId:result.credentialId}),new Response(JSON.stringify({success:!0,data:{user:{id:user.id,email:user.email},accessToken,refreshToken,sessionId}}),{status:200,headers})}}),routeGetCredentials=defineRoute({method:"GET",path:"/credentials",handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};return{success:!0,data:{credentials:(await webauthnService.listUserCredentials(userId,getSchema(ctx))).map((cred)=>({id:cred.id,credentialId:cred.credentialId,nickname:cred.nickname,deviceType:cred.deviceType,backedUp:cred.backedUp,authenticatorAttachment:cred.authenticatorAttachment,transports:cred.transports,aaguid:cred.aaguid,lastUsedAt:cred.lastUsedAt,revokedAt:cred.revokedAt,createdAt:cred.createdAt}))}}}}),routeDeleteCredentialsCredentialid=defineRoute({method:"DELETE",path:"/credentials/:credentialId",handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{credentialId}=ctx.params;if(!await webauthnService.revokeCredential(credentialId,userId,getSchema(ctx)))return ctx.set.status=404,{success:!1,message:"Credential not found"};return{success:!0,message:"Credential revoked"}}}),routePatchCredentialsCredentialid=defineRoute({method:"PATCH",path:"/credentials/:credentialId",body:WebAuthnRenameSchema,handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{credentialId}=ctx.params,body=ctx.body;if(!await webauthnService.renameCredential(credentialId,userId,body.nickname,getSchema(ctx)))return ctx.set.status=404,{success:!1,message:"Credential not found"};return{success:!0,message:"Credential renamed"}}});return collectRoutes([{prefix:basePath,routes:[routePostRegisterOptions,routePostRegisterVerify,routePostAuthenticateOptions,routePostAuthenticateVerify,routeGetCredentials,routeDeleteCredentialsCredentialid,routePatchCredentialsCredentialid]}])}var init_webauthn=__esm(()=>{init_DeviceTrust();init_routeCollector();init_fetchUserRolesAndClaims();init_deviceInfo();init_types21();init_types21()});var exports_auth={};__export(exports_auth,{createWebAuthnRoute:()=>createWebAuthnRoute,createSessionsRoute:()=>createSessionsRoute,createRegisterRoute:()=>createRegisterRoute,createRefreshRoute:()=>createRefreshRoute,createPasswordSetRoute:()=>createPasswordSetRoute,createPasswordResetRoute:()=>createPasswordResetRoute,createPasswordChangeRoute:()=>createPasswordChangeRoute,createMeRoute:()=>createMeRoute,createMagicLinkRoute:()=>createMagicLinkRoute,createLogoutRoute:()=>createLogoutRoute,createLoginRoute:()=>createLoginRoute,createInviteRoute:()=>createInviteRoute,createImpersonateRoute:()=>createImpersonateRoute,createHardDeleteUserRoute:()=>createHardDeleteUserRoute,createEmailVerificationRoutes:()=>createEmailVerificationRoutes,createCreateUserRoute:()=>createCreateUserRoute,createChangeUserIdRoute:()=>createChangeUserIdRoute,createAuthRoutes:()=>createAuthRoutes,createApiKeyRoutes:()=>createApiKeyRoutes});function createAuthRoutes(app,config){let{authConfig,features,helpers:helpers3}=config;if(config.oauthAccountsTable)authConfig.oauthAccountsTable=config.oauthAccountsTable;if(config.schemaTables)authConfig.schemaTables=config.schemaTables;if(config.tenantRegistry)authConfig.tenantRegistry=config.tenantRegistry;if(config.getTenantRegistry)authConfig.getTenantRegistry=config.getTenantRegistry;let buffer=authConfig.authentication?.cookieMaxAgeBufferSeconds??0,rawCookieDomain=authConfig.authentication?.cookieDomain,resolvedCookieDomainRaw=rawCookieDomain?process.env[rawCookieDomain]??rawCookieDomain:void 0,resolvedCookieDomain=resolvedCookieDomainRaw==="localhost"||resolvedCookieDomainRaw===".localhost"?void 0:resolvedCookieDomainRaw,isLocalDev=!resolvedCookieDomain,cookieConfig={accessTokenName:authConfig.authentication?.accessToken?.name||"access_token",refreshTokenName:authConfig.authentication?.refreshToken?.name||"refresh_token",sessionTokenName:authConfig.authentication?.sessionToken?.name||"session_token",accessTokenMaxAge:Math.max(0,parseTimeToSeconds2(authConfig.authentication?.accessToken?.expiresIn||"15m")-buffer),refreshTokenMaxAge:parseTimeToSeconds2(authConfig.authentication?.refreshToken?.expiresIn||"7d"),sessionTokenMaxAge:parseTimeToSeconds2(authConfig.authentication?.sessionToken?.expiresIn||"30d"),domain:resolvedCookieDomain,secure:!isLocalDev,httpOnly:!0,sameSite:"lax",path:"/"};if(authConfig.logger.info("[AUTH] Cookie config created",{accessTokenMaxAge:cookieConfig.accessTokenMaxAge,refreshTokenMaxAge:cookieConfig.refreshTokenMaxAge,sessionTokenMaxAge:cookieConfig.sessionTokenMaxAge,accessTokenExpiresIn:authConfig.authentication?.accessToken?.expiresIn,sessionTokenExpiresIn:authConfig.authentication?.sessionToken?.expiresIn}),features.login?.enabled){let loginRoutes=createLoginRoute(authConfig,features.login,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.createSession,helpers3.saveSessionToDb,cookieConfig,config.tokenResponseConfig,config.captchaService??void 0);useRoutes(app,loginRoutes)}if(features.register?.enabled){let registerRoutes=createRegisterRoute(authConfig,features.register,helpers3.sendWelcomeEmail,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.createSession,cookieConfig,config.tokenResponseConfig,config.getEmailService,config.appName,helpers3.saveSessionToDb);if(useRoutes(app,registerRoutes),features.register.emailVerification?.enabled){let emailVerificationRoutes=createEmailVerificationRoutes({authConfig,registerConfig:features.register,getEmailService:config.getEmailService,appName:config.appName});useRoutes(app,emailVerificationRoutes)}}if(features.logout?.enabled){let logoutRoutes=createLogoutRoute(authConfig,features.logout,helpers3.destroySession,helpers3.revokeSessionInDb,cookieConfig);useRoutes(app,logoutRoutes)}if(features.refresh?.enabled){let refreshRoutes=createRefreshRoute(authConfig,features.refresh,helpers3.verifyRefreshToken,helpers3.signAccessToken,helpers3.signRefreshToken,config.tokenResponseConfig,buffer,cookieConfig);useRoutes(app,refreshRoutes)}if(features.passwordReset?.enabled&&helpers3.storeResetToken&&helpers3.getResetToken&&helpers3.deleteResetToken){let passwordResetRoutes=createPasswordResetRoute(authConfig,features.passwordReset,helpers3.storeResetToken,helpers3.getResetToken,helpers3.deleteResetToken,helpers3.sendResetEmail);useRoutes(app,passwordResetRoutes)}if(features.passwordChange?.enabled){let passwordChangeRoutes=createPasswordChangeRoute(authConfig,features.passwordChange);useRoutes(app,passwordChangeRoutes)}if(features.passwordSet?.enabled){let passwordSetRoutes=createPasswordSetRoute(authConfig,features.passwordSet,helpers3.getMagicToken,helpers3.deleteMagicToken);useRoutes(app,passwordSetRoutes)}if(features.sessions?.enabled&&config.sessionsTable){let sessionsRoutes=createSessionsRoute(authConfig,features.sessions,config.sessionsTable);useRoutes(app,sessionsRoutes)}if(features.magicLink?.enabled&&helpers3.storeMagicToken&&helpers3.getMagicToken&&helpers3.deleteMagicToken){let magicLinkRoutes=createMagicLinkRoute(authConfig,features.magicLink,config.getEmailService,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.createSession,helpers3.storeMagicToken,helpers3.getMagicToken,helpers3.deleteMagicToken,config.appName,cookieConfig,helpers3.saveSessionToDb);useRoutes(app,magicLinkRoutes)}if(features.me?.enabled){let meRoutes=createMeRoute(authConfig,features.me,config.schemaTables||{},config.schemaRelations||{},config.databaseUrl);useRoutes(app,meRoutes)}if(features.invite?.enabled&&helpers3.storeMagicToken){let inviteRoutes=createInviteRoute(authConfig,features.invite,config.getEmailService,helpers3.storeMagicToken,config.appName,helpers3.getMagicToken);useRoutes(app,inviteRoutes)}if(features.captcha?.enabled&&config.captchaService){let captchaRoutes=createCaptchaRoutes({captchaService:config.captchaService,logger:authConfig.logger,basePath:features.captcha.route||"/auth/captcha"});useRoutes(app,captchaRoutes)}if(features.oauth?.enabled&&features.oauth.providers){let oauthService=new OAuthService(features.oauth,config.oauthStateStore),oauthRoutes=createOAuthRoutes(authConfig,oauthService,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.createSession,helpers3.saveSessionToDb,cookieConfig,config.tokenResponseConfig,config.getEmailService,helpers3.storeMagicToken,config.appName);useRoutes(app,oauthRoutes)}if(features.apiKeys?.enabled&&config.apiKeysTable)authConfig.apiKeysTable=config.apiKeysTable,createApiKeyRoutes(app,authConfig,features.apiKeys);if(features.webauthn?.enabled&&config.webauthnService){let webauthnRoutes=createWebAuthnRoute(authConfig,{basePath:features.webauthn.route||"/auth/webauthn",isPublic:features.webauthn.isPublic,enabled:!0},config.webauthnService,{signAccessToken:helpers3.signAccessToken,signRefreshToken:helpers3.signRefreshToken,createSession:helpers3.createSession,saveSessionToDb:helpers3.saveSessionToDb},cookieConfig);useRoutes(app,webauthnRoutes)}let checkRoutes=createCheckRoute(authConfig,{route:"/auth/check",isPublic:!1,enabled:!0});if(useRoutes(app,checkRoutes),config.admin?.impersonate?.enabled!==!1){let impersonateRoutes=createImpersonateRoute(authConfig,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.verifyRefreshToken,helpers3.createSession,helpers3.saveSessionToDb,cookieConfig);useRoutes(app,impersonateRoutes)}if(config.admin?.changeUserId?.enabled!==!1){let changeUserIdRoutes=createChangeUserIdRoute(authConfig,config.schemaName||"public");useRoutes(app,changeUserIdRoutes)}if(config.admin?.createUser?.enabled!==!1){let createUserRoutes=createCreateUserRoute(authConfig,config.admin?.createUser);useRoutes(app,createUserRoutes)}if(useRoutes(app,createPasswordAdminRoutes(authConfig,{passwordTools:config.admin?.passwordTools?.enabled===!0})),useRoutes(app,createUserStateRoutes(authConfig)),config.admin?.hardDelete?.enabled!==!1){let hardDeleteRoutes=createHardDeleteUserRoute(authConfig);useRoutes(app,hardDeleteRoutes)}return app}var init_auth=__esm(()=>{init_OAuth();init_routeMount();init_utils5();init_changeUserId();init_createUser();init_hardDeleteUser();init_impersonate();init_passwordAdmin();init_userState();init_apiKeys();init_captcha();init_check();init_emailVerification();init_invite();init_login();init_logout();init_magicLink();init_me();init_oauth();init_passwordChange();init_passwordReset();init_passwordSet();init_refresh();init_register();init_sessions();init_webauthn();init_changeUserId();init_createUser();init_hardDeleteUser();init_impersonate();init_apiKeys();init_emailVerification();init_invite();init_login();init_logout();init_magicLink();init_me();init_passwordChange();init_passwordReset();init_passwordSet();init_refresh();init_register();init_sessions();init_webauthn()});var exports_backup={};__export(exports_backup,{createBackupRoutes:()=>createBackupRoutes});function createBackupRoutes(routeConfig){let{db,logger:logger2,schemaTables,schemaName,getTenantRegistry,lock}=routeConfig,config={...DEFAULT_BACKUP_CONFIG,...routeConfig.config},basePath=config.basePath,backupLogsTable=schemaTables.backupLogs||schemaTables.backup_logs,backupService=new BackupService({db,logger:logger2,config,schemaTables,schemaName,backupLogsTable,lock});if(config.schedule.enabled)backupService.startScheduler();let guard4=createGodminGuard({db,schemaTables,logger:logger2},"backup management"),resolveTargetSchema=(targetSchema)=>{if(!targetSchema||targetSchema===schemaName)return{ok:!0,name:schemaName,tables:schemaTables};let tenantCtx=getTenantRegistry?.()?.getSchemaContext(targetSchema);if(!tenantCtx)return{ok:!1,message:`Schema not found: ${targetSchema}`};return{ok:!0,name:targetSchema,tables:tenantCtx.schemaTables}},declared=[defineRoute({method:"POST",path:basePath,handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let body=ctx.body,target2=resolveTargetSchema(body?.schema);if(!target2.ok)return ctx.set.status=404,{success:!1,message:target2.message};let result=await backupService.createBackup("manual",userId,target2.name,target2.tables);if(result.status==="failed")return ctx.set.status=500,{success:!1,message:result.errorMessage||"Backup failed"};return{success:!0,message:"Backup created successfully",data:{id:result.id,backupName:result.backupName,schemaName:result.schemaName,tableCount:result.tableCount,rowCount:result.rowCount,sizeBytes:result.sizeBytes,status:result.status}}},body:Type.Optional(Type.Object({schema:Type.Optional(Type.String())})),detail:{tags:["Backup"],summary:"Create backup",description:"Create a new database backup. Optionally specify a schema for multi-tenant backups."}}),defineRoute({method:"GET",path:basePath,handler:async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,message:"Authentication required",data:null};let backups=await backupService.listBackups();return{success:!0,data:{items:backups,totalCount:backups.length}}},detail:{tags:["Backup"],summary:"List backups",description:"List all backup records."}}),defineRoute({method:"GET",path:`${basePath}/:id/download`,handler:async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,message:"Authentication required"};let{id}=ctx.params,filePath=await backupService.getBackupFilePath(id);if(!filePath)return ctx.set.status=404,{success:!1,message:"Backup not found"};try{let{readFile:readFile2}=await import("fs/promises"),content=await readFile2(filePath,"utf-8");return new Response(content,{headers:{"Content-Type":"application/json","Content-Disposition":`attachment; filename="${id}.json"`}})}catch{return ctx.set.status=404,{success:!1,message:"Backup file not found on disk"}}},detail:{tags:["Backup"],summary:"Download backup",description:"Download a backup file by ID."}}),defineRoute({method:"POST",path:`${basePath}/:id/restore`,handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!config.allowRestore)return ctx.set.status=403,{success:!1,message:"Restore is disabled in configuration"};let{id}=ctx.params,restoreBody=ctx.body,target2=resolveTargetSchema(restoreBody?.schema);if(!target2.ok)return ctx.set.status=404,{success:!1,message:target2.message};let result=await backupService.restoreFromBackup(id,userId,target2.name,target2.tables);if(!result.success)return ctx.set.status=400,result;return await logger2.audit({entityName:"backup_logs",entityId:id,operation:"RESTORE",userId,summary:`Database restored from backup ${id}`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:new URL(ctx.request.url).pathname,query:""}),result},detail:{tags:["Backup"],summary:"Restore from backup",description:"Restore database from a specific backup. Creates a pre-restore backup automatically."}}),defineRoute({method:"DELETE",path:`${basePath}/:id`,handler:async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,message:"Authentication required"};let{id}=ctx.params;if(!await backupService.deleteBackup(id))return ctx.set.status=404,{success:!1,message:"Backup not found"};return{success:!0,message:"Backup deleted"}},detail:{tags:["Backup"],summary:"Delete backup",description:"Delete a specific backup and its file."}})];return{routes:collectRoutes([{guards:[guard4],routes:declared}]),backupService}}var DEFAULT_BACKUP_CONFIG;var init_backup=__esm(()=>{init_esm3();init_Backup();init_routeCollector();init_adminGuard();DEFAULT_BACKUP_CONFIG={enabled:!1,basePath:"/admin/backup",storagePath:"./backups",format:"json",maxBackups:50,allowRestore:!0,excludeTables:["audit_logs","backup_logs"],schedule:{enabled:!1,cron:"0 2 * * *",retentionDays:30}}});var validateAmount=(v,field="amount",opts={})=>{if(typeof v!=="number"||!Number.isFinite(v))return{ok:!1,error:`${field} must be a finite number`};if(opts.allowZero?v<0:v<=0)return{ok:!1,error:`${field} must be ${opts.allowZero?">= 0":"> 0"}`};return{ok:!0,value:v}},isValidCurrency=(v)=>v===void 0||v===null||typeof v==="string"&&/^[A-Za-z]{3}$/.test(v);import{eq as eq65}from"drizzle-orm";var col15=(table,name2)=>table[name2],str4=(v)=>typeof v==="string"?v:null,num3=(v)=>typeof v==="number"?v:null,handleChargeRefunded=async(deps,obj)=>{let candidates=[str4(obj.id),str4(obj.payment_intent)].filter((v)=>v!==null);for(let candidate of candidates){let updated=await deps.db.update(deps.transactionsTable).set({status:"refunded",refundedAmount:num3(obj.amount_refunded)??void 0,refundedAt:new Date,statusMessage:"Refunded via Stripe webhook",updatedAt:new Date}).where(eq65(col15(deps.transactionsTable,"providerPaymentId"),candidate)).returning();if(Array.isArray(updated)&&updated.length>0)return}},handleDisputeCreated=async(deps,obj)=>{let payoutService=deps.getPayoutService?.();if(!payoutService)return;let metadata=obj.metadata??{};await payoutService.openDispute({provider:"stripe",providerDisputeId:str4(obj.id)??void 0,ownerType:str4(metadata.ownerType)==="seller"?"seller":void 0,ownerId:str4(metadata.ownerId)??void 0,amount:num3(obj.amount)??void 0,currency:str4(obj.currency)?.toUpperCase(),reason:str4(obj.reason)??void 0})},handleDisputeClosed=async(deps,obj)=>{let payoutService=deps.getPayoutService?.(),providerId=str4(obj.id);if(!payoutService||!providerId)return;await payoutService.reconcileDisputeByProvider(providerId,str4(obj.status)??"")},handlePayoutOutcome=async(deps,obj,outcome,reason)=>{let payoutService=deps.getPayoutService?.(),providerId=str4(obj.id);if(!payoutService||!providerId)return;await payoutService.reconcilePayoutByProvider(providerId,outcome,reason)},dispatch=async(deps,eventType,obj)=>{switch(eventType){case"charge.refunded":await handleChargeRefunded(deps,obj);break;case"charge.dispute.created":await handleDisputeCreated(deps,obj);break;case"charge.dispute.closed":case"charge.dispute.funds_reinstated":await handleDisputeClosed(deps,obj);break;case"payout.paid":await handlePayoutOutcome(deps,obj,"completed");break;case"payout.failed":case"payout.canceled":await handlePayoutOutcome(deps,obj,"failed",str4(obj.failure_message)??eventType);break;case"transfer.reversed":await handlePayoutOutcome(deps,obj,"failed","transfer reversed");break;default:break}},createStripeWebhookRoute=(deps)=>{return defineRoute({method:"POST",path:"/webhook",handler:async(ctx)=>{if(deps.provider.name!=="stripe")return ctx.set.status=501,{received:!1,error:"Webhooks are only supported for the Stripe provider"};if(!deps.webhookSecret)return deps.logger.error("[Payment] Webhook received but STRIPE_WEBHOOK_SECRET is not configured"),ctx.set.status=500,{received:!1,error:"Webhook secret not configured"};let rawBody=await ctx.request.text(),signature=ctx.request.headers.get("stripe-signature")??"",verified=await verifyStripeWebhook(rawBody,signature,deps.webhookSecret);if(!verified.success||!verified.event)return deps.logger.warn("[Payment] Webhook signature verification failed",{error:verified.error}),ctx.set.status=400,{received:!1,error:"Invalid signature"};let event=verified.event,eventId=str4(event.id)??"",eventType=str4(event.type)??"",obj=event.data?.object??{},idempotencyKey=`stripe:${eventId}`,inserted=await deps.db.insert(deps.webhookLogsTable).values({provider:"stripe",eventType,providerPaymentId:str4(obj.payment_intent)??str4(obj.id),rawPayload:event,processed:!1,idempotencyKey,ipAddress:ctx.request.headers.get("x-forwarded-for")??ctx.request.headers.get("x-real-ip")??null}).onConflictDoNothing().returning();if(!Array.isArray(inserted)||inserted.length===0)return{received:!0,duplicate:!0,eventType};try{return await dispatch(deps,eventType,obj),await deps.db.update(deps.webhookLogsTable).set({processed:!0,processingResult:{ok:!0},updatedAt:new Date}).where(eq65(col15(deps.webhookLogsTable,"idempotencyKey"),idempotencyKey)),deps.logger.info("[Payment] Webhook processed",{eventType,eventId}),{received:!0,eventType}}catch(err){let message=err instanceof Error?err.message:String(err);return deps.logger.error("[Payment] Webhook handler failed",{eventType,error:message}),await deps.db.update(deps.webhookLogsTable).set({errorMessage:message,updatedAt:new Date}).where(eq65(col15(deps.webhookLogsTable,"idempotencyKey"),idempotencyKey)).catch(()=>{}),ctx.set.status=500,{received:!1,error:"Handler error"}}}})};var init_webhook=__esm(()=>{init_Payment()});var exports_payment={};__export(exports_payment,{createPaymentRoutes:()=>createPaymentRoutes});import{and as and28,eq as eq66,inArray as inArray20,ne as ne4,or as or5,sql as sql13}from"drizzle-orm";var escapeHtml2=(value2)=>value2.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),generateRedirectHtml=(url,title)=>{let safeTitle=escapeHtml2(title),safeUrlAttr=escapeHtml2(url),safeUrlJs=JSON.stringify(url).replace(/</g,"\\u003c").replace(/>/g,"\\u003e");return`
|
|
525
|
+
</body></html>`},routeGetApprovePage=defineRoute({method:"GET",path:"/approve-page",detail:{tags:["Authentication"],summary:"Approval page",description:"Standalone HTML page for approving a device (no frontend auth required)"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return new Response("Service unavailable",{status:503});let token=new URL(ctx.request.url).searchParams.get("token");if(!token){let html2=buildApprovalPageHtml({},"approve","","invalid");return new Response(html2,{status:400,headers:{"Content-Type":"text/html; charset=utf-8"}})}let sessions=await db.select().from(sessionsTable2).where(eq63(col15("approvalToken"),token)).limit(1);if(sessions.length===0){let html2=buildApprovalPageHtml({},"approve",token,"invalid");return new Response(html2,{status:404,headers:{"Content-Type":"text/html; charset=utf-8"}})}let session=sessions[0];if(session.approvalStatus!=="pending"&&session.approval_status!=="pending"){let html2=buildApprovalPageHtml(session,"approve",token,"already_processed");return new Response(html2,{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}})}let requestedAt=session.approvalRequestedAt||session.approval_requested_at;if(requestedAt&&Date.now()-new Date(requestedAt).getTime()>APPROVAL_TOKEN_TTL_MS){let html2=buildApprovalPageHtml(session,"approve",token,"expired");return new Response(html2,{status:410,headers:{"Content-Type":"text/html; charset=utf-8"}})}let html=buildApprovalPageHtml(session,"approve",token,"pending");return new Response(html,{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}})}}),routeGetRejectPage=defineRoute({method:"GET",path:"/reject-page",detail:{tags:["Authentication"],summary:"Rejection page",description:"Standalone HTML page for rejecting a device (no frontend auth required)"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return new Response("Service unavailable",{status:503});let token=new URL(ctx.request.url).searchParams.get("token");if(!token){let html2=buildApprovalPageHtml({},"reject","","invalid");return new Response(html2,{status:400,headers:{"Content-Type":"text/html; charset=utf-8"}})}let sessions=await db.select().from(sessionsTable2).where(eq63(col15("approvalToken"),token)).limit(1);if(sessions.length===0){let html2=buildApprovalPageHtml({},"reject",token,"invalid");return new Response(html2,{status:404,headers:{"Content-Type":"text/html; charset=utf-8"}})}let session=sessions[0];if(session.approvalStatus!=="pending"&&session.approval_status!=="pending"){let html2=buildApprovalPageHtml(session,"reject",token,"already_processed");return new Response(html2,{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}})}let requestedAt=session.approvalRequestedAt||session.approval_requested_at;if(requestedAt&&Date.now()-new Date(requestedAt).getTime()>APPROVAL_TOKEN_TTL_MS){let html2=buildApprovalPageHtml(session,"reject",token,"expired");return new Response(html2,{status:410,headers:{"Content-Type":"text/html; charset=utf-8"}})}let html=buildApprovalPageHtml(session,"reject",token,"pending");return new Response(html,{status:200,headers:{"Content-Type":"text/html; charset=utf-8"}})}}),routeGetApprovalStatus=defineRoute({method:"GET",path:"/approval-status",detail:{tags:["Authentication"],summary:"Check approval status",description:"Check the approval status of a pending session"},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let sessionId=new URL(ctx.request.url).searchParams.get("sessionId");if(!sessionId)return ctx.set.status=400,{success:!1,message:"sessionId is required"};let sessions=await db.select().from(sessionsTable2).where(eq63(col15("id"),sessionId)).limit(1);if(sessions.length===0)return ctx.set.status=404,{success:!1,message:"Session not found"};let session=sessions[0];return{success:!0,data:{approvalStatus:session.approvalStatus||session.approval_status||"unknown",isActive:session.isActive||session.is_active}}}}),routeGetDevices=defineRoute({method:"GET",path:"/devices",detail:{tags:["Authentication"],summary:"List remembered devices",description:"List the caller's remembered (device-trust) devices; never returns the token."},handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let dtTable=getSessionsForRequest(ctx.request).trustedDevicesTable;if(!dtTable||!db)return{success:!0,data:{items:[]}};let{listUserDevices:listUserDevices2}=await Promise.resolve().then(() => (init_store3(),exports_store));return{success:!0,data:{items:await listUserDevices2(db,dtTable,userId)}}}}),routeDeleteDevicesId=defineRoute({method:"DELETE",path:"/devices/:id",detail:{tags:["Authentication"],summary:"Revoke a remembered device",description:"Owner-scoped revoke of one remembered device (untrusts it)."},handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let id=ctx.params.id,dtTable=getSessionsForRequest(ctx.request).trustedDevicesTable;if(!dtTable||!db)return ctx.set.status=503,{success:!1,message:"Device trust not enabled"};let{revokeDeviceById:revokeDeviceById2}=await Promise.resolve().then(() => (init_store3(),exports_store));if(await revokeDeviceById2(db,dtTable,id,userId,"user_revoked")===0)return ctx.set.status=404,{success:!1,message:"Device not found"};return log4.info("Remembered device revoked",{userId,deviceId:id}),{success:!0,message:"Device revoked"}}}),adminGuard=createGodminGuard2({logger:logger2,db,schemaTables:config.schemaTables??{},area:"session management",allowedRoles:sessionsConfig.adminRoles??[]}),routeGetAdminUserid=defineRoute({method:"GET",path:"/admin/:userId",guards:[adminGuard],detail:{tags:["Authentication"],summary:"List another user's active sessions (admin)",description:"Godmin or a role named in authentication.sessions.adminRoles. Used for offboarding and lost-device response."},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{userId}=ctx.params,sessions=await db.select().from(sessionsTable2).where(and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0),isNull5(col15("revokedAt")))).orderBy(desc6(col15("lastActivityAt")));return{success:!0,data:{sessions:sessions.map((session)=>formatSessionForResponse(session)),totalCount:sessions.length}}}}),routeDeleteAdminUserid=defineRoute({method:"DELETE",path:"/admin/:userId",guards:[adminGuard],body:AdminRevokeSessionsBodySchema,detail:{tags:["Authentication"],summary:"End another user's sessions (admin)",description:"Ends every active session of the given user, or just one when `sessionId` is supplied. Godmin or authentication.sessions.adminRoles."},handler:async(ctx)=>{let{sessionsTable:sessionsTable2,col:col15}=getSessionsForRequest(ctx.request);if(!db)return ctx.set.status=500,{success:!1,message:"Database not configured"};let{userId}=ctx.params,body=ctx.body??{},actorId=ctx.request.headers.get("x-user-id")||void 0,target2=body.sessionId?and27(eq63(col15("id"),body.sessionId),eq63(col15("userId"),userId),eq63(col15("isActive"),!0)):and27(eq63(col15("userId"),userId),eq63(col15("isActive"),!0)),affected=await db.update(sessionsTable2).set({isActive:!1,revokedAt:new Date,revokedReason:body.reason||"admin_revoked"}).where(target2).returning({id:col15("id")});log4.warn("Sessions revoked by an administrator",{actorId,subjectUserId:userId,sessionId:body.sessionId,revoked:affected.length,reason:body.reason||"admin_revoked"});let reqUrl=new URL(ctx.request.url);return logger2.audit({entityName:"user_sessions",entityId:body.sessionId,operation:"SESSION_REVOKE_ALL",userId:actorId,summary:body.sessionId?`Admin revoked one session of user ${userId}`:`Admin revoked ${affected.length} session(s) of user ${userId}`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:reqUrl.pathname,query:reqUrl.search}),{success:!0,message:`${affected.length} session${affected.length===1?"":"s"} ended`,data:{revoked:affected.length}}}});return collectRoutes([{prefix:baseRoute,routes:[routeGetRoot,routeGetCurrent,routeDeleteSessionid,routeDeleteAll,routeGetStats,routePostApprove,routePostReject,routeGetPending,routeGetApprovePage,routeGetRejectPage,routeGetApprovalStatus,routeGetDevices,routeDeleteDevicesId,routeGetAdminUserid,routeDeleteAdminUserid]}])}var init_sessions=__esm(()=>{init_Delete2();init_scopes();init_routeCollector();init_godminGuard();init_types20();init_utils11();init_types20()});function resolveCookies(cookieConfig){return{accessTokenName:cookieConfig?.accessTokenName||"access_token",refreshTokenName:cookieConfig?.refreshTokenName||"refresh_token",sessionTokenName:cookieConfig?.sessionTokenName||"session_token",accessTokenMaxAge:cookieConfig?.accessTokenMaxAge||900,refreshTokenMaxAge:cookieConfig?.refreshTokenMaxAge||604800,sessionTokenMaxAge:cookieConfig?.sessionTokenMaxAge||2592000,secure:cookieConfig?.secure??!0,httpOnly:cookieConfig?.httpOnly??!0,sameSite:cookieConfig?.sameSite||"lax",path:cookieConfig?.path||"/",domain:cookieConfig?.domain}}function buildCookieHeaders(cookies,tokens){let securePart=cookies.secure?"; Secure":"",domainPart=cookies.domain?`; Domain=${cookies.domain}`:"",cookieOptions=`; Path=${cookies.path}; HttpOnly; SameSite=${cookies.sameSite}${securePart}${domainPart}`,headers=new Headers;return headers.set("Content-Type","application/json"),headers.set("x-session-id",tokens.sessionId),headers.append("Set-Cookie",`${cookies.accessTokenName}=${tokens.accessToken}${cookieOptions}; Max-Age=${cookies.accessTokenMaxAge}`),headers.append("Set-Cookie",`${cookies.refreshTokenName}=${tokens.refreshToken}${cookieOptions}; Max-Age=${cookies.refreshTokenMaxAge}`),headers.append("Set-Cookie",`${cookies.sessionTokenName}=${tokens.sessionId}${cookieOptions}; Max-Age=${cookies.sessionTokenMaxAge}`),headers}var WebAuthnRegisterOptionsSchema,WebAuthnRegisterVerifySchema,WebAuthnAuthOptionsSchema,WebAuthnAuthVerifySchema,WebAuthnRenameSchema;var init_types21=__esm(()=>{init_esm3();WebAuthnRegisterOptionsSchema=Type.Object({nickname:Type.Optional(Type.String({maxLength:128}))}),WebAuthnRegisterVerifySchema=Type.Object({response:Type.Any(),challenge:Type.String(),nickname:Type.Optional(Type.String({maxLength:128}))}),WebAuthnAuthOptionsSchema=Type.Object({email:Type.Optional(Type.String({format:"email"}))}),WebAuthnAuthVerifySchema=Type.Object({response:Type.Any(),challenge:Type.String(),rememberMe:Type.Optional(Type.Boolean())}),WebAuthnRenameSchema=Type.Object({nickname:Type.String({minLength:1,maxLength:128})})});import{eq as eq64}from"drizzle-orm";function getSchema(ctx){return ctx.request.headers.get("x-tenant-schema")||void 0}function getUserId2(ctx){return ctx.request.headers.get("x-user-id")}function createWebAuthnRoute(config,routeOptions,webauthnService,helpers3,cookieConfig){let{db,logger:logger2}=config,basePath=routeOptions.basePath||"/auth/webauthn",cookies=resolveCookies(cookieConfig);if(!routeOptions.enabled)return collectRoutes();let routePostRegisterOptions=defineRoute({method:"POST",path:"/register/options",body:WebAuthnRegisterOptionsSchema,handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let user=(await db.select().from(usersTable).where(eq64(usersTable.id,userId)).limit(1))[0];if(!user)return ctx.set.status=404,{success:!1,message:"User not found"};return{success:!0,data:await webauthnService.createRegistrationOptions({userId,userName:user.email||userId,userDisplayName:user.email||userId,schemaName:getSchema(ctx)})}}}),routePostRegisterVerify=defineRoute({method:"POST",path:"/register/verify",body:WebAuthnRegisterVerifySchema,handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let body=ctx.body,credential=await webauthnService.verifyRegistration({response:body.response,expectedChallenge:body.challenge,userId,nickname:body.nickname,schemaName:getSchema(ctx)});if(!credential)return logger2.warn("[WEBAUTHN] Registration verification failed",{userId}),ctx.set.status=400,{success:!1,message:"Registration failed"};return{success:!0,data:{id:credential.id,credentialId:credential.credentialId,nickname:credential.nickname,deviceType:credential.deviceType,backedUp:credential.backedUp,authenticatorAttachment:credential.authenticatorAttachment,aaguid:credential.aaguid,transports:credential.transports,lastUsedAt:credential.lastUsedAt,revokedAt:credential.revokedAt,createdAt:credential.createdAt}}}}),routePostAuthenticateOptions=defineRoute({method:"POST",path:"/authenticate/options",body:WebAuthnAuthOptionsSchema,handler:async(ctx)=>{let body=ctx.body,resolvedUserId;if(body.email){let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(db&&usersTable){let user=(await db.select().from(usersTable).where(eq64(usersTable.email,body.email.toLowerCase())).limit(1))[0];if(user)resolvedUserId=user.id}}return{success:!0,data:await webauthnService.createAuthenticationOptions({userId:resolvedUserId,schemaName:getSchema(ctx)})}}}),routePostAuthenticateVerify=defineRoute({method:"POST",path:"/authenticate/verify",body:WebAuthnAuthVerifySchema,handler:async(ctx)=>{let body=ctx.body,result=await webauthnService.verifyAuthentication({response:body.response,expectedChallenge:body.challenge,schemaName:getSchema(ctx)});if(!result.verified||!result.userId)return ctx.set.status=401,{success:!1,message:"Authentication failed"};let{usersTable}=resolveAuthTablesForRequest(ctx.request,config);if(!db||!usersTable)return ctx.set.status=500,{success:!1,message:"Database not configured"};let user=(await db.select().from(usersTable).where(eq64(usersTable.id,result.userId)).limit(1))[0];if(!user)return ctx.set.status=401,{success:!1,message:"User not found"};let webauthnState=evaluateAccountState(user);if(!webauthnState.allowed)return ctx.set.status=401,{success:!1,message:webauthnState.message};let roles=[],claims=[],claimScopes={};try{let resolved=resolveAuthTablesForRequest(ctx.request,config),rc=await fetchUserRolesAndClaims(db,result.userId,resolved);roles=rc.roles,claims=rc.claims,claimScopes=rc.claimScopes}catch{}let ipAddress=ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||ctx.request.headers.get("x-real-ip")?.trim()||"unknown",userAgent=ctx.request.headers.get("user-agent")||"",sessionParams={userId:result.userId,deviceInfo:ensureDeviceInfo({ipAddress,userAgent},deviceContextFromRequest(ctx.request).clientHints),loginMethod:"webauthn",rememberMe:body.rememberMe??!1},sessionId=await helpers3.createSession(sessionParams),accessToken=helpers3.signAccessToken(result.userId,roles.length>0?roles:void 0,claims.length>0?claims:void 0,getSchema(ctx),claimScopes,sessionId),refreshToken=helpers3.signRefreshToken(result.userId,body.rememberMe??!1,sessionId),deviceTokenCookie;if(helpers3.saveSessionToDb){let dtCfg=config.authentication?.deviceTrust;if(dtCfg?.enabled)sessionParams.deviceToken=readDeviceTokenFromCookieHeader(ctx.request.headers.get("cookie"),dtCfg);let saveResult=await helpers3.saveSessionToDb(sessionId,sessionParams,getSchema(ctx));if(saveResult?.denied)return ctx.set.status=403,{success:!1,message:"This device could not be recognized. Please contact support."};if(deviceTokenCookie=saveResult?.deviceTokenCookie,saveResult?.requiresApproval){if(deviceTokenCookie)ctx.set.headers["Set-Cookie"]=deviceTokenCookie;return ctx.set.status=202,{success:!1,requiresApproval:!0,sessionId:saveResult.sessionId??sessionId,message:"Login requires approval"}}}let headers=buildCookieHeaders(cookies,{accessToken,refreshToken,sessionId});if(deviceTokenCookie)headers.append("Set-Cookie",deviceTokenCookie);return logger2.info("[WEBAUTHN] Authentication successful",{userId:result.userId,credentialId:result.credentialId}),new Response(JSON.stringify({success:!0,data:{user:{id:user.id,email:user.email},accessToken,refreshToken,sessionId}}),{status:200,headers})}}),routeGetCredentials=defineRoute({method:"GET",path:"/credentials",handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};return{success:!0,data:{credentials:(await webauthnService.listUserCredentials(userId,getSchema(ctx))).map((cred)=>({id:cred.id,credentialId:cred.credentialId,nickname:cred.nickname,deviceType:cred.deviceType,backedUp:cred.backedUp,authenticatorAttachment:cred.authenticatorAttachment,transports:cred.transports,aaguid:cred.aaguid,lastUsedAt:cred.lastUsedAt,revokedAt:cred.revokedAt,createdAt:cred.createdAt}))}}}}),routeDeleteCredentialsCredentialid=defineRoute({method:"DELETE",path:"/credentials/:credentialId",handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{credentialId}=ctx.params;if(!await webauthnService.revokeCredential(credentialId,userId,getSchema(ctx)))return ctx.set.status=404,{success:!1,message:"Credential not found"};return{success:!0,message:"Credential revoked"}}}),routePatchCredentialsCredentialid=defineRoute({method:"PATCH",path:"/credentials/:credentialId",body:WebAuthnRenameSchema,handler:async(ctx)=>{let userId=getUserId2(ctx);if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let{credentialId}=ctx.params,body=ctx.body;if(!await webauthnService.renameCredential(credentialId,userId,body.nickname,getSchema(ctx)))return ctx.set.status=404,{success:!1,message:"Credential not found"};return{success:!0,message:"Credential renamed"}}});return collectRoutes([{prefix:basePath,routes:[routePostRegisterOptions,routePostRegisterVerify,routePostAuthenticateOptions,routePostAuthenticateVerify,routeGetCredentials,routeDeleteCredentialsCredentialid,routePatchCredentialsCredentialid]}])}var init_webauthn=__esm(()=>{init_DeviceTrust();init_routeCollector();init_fetchUserRolesAndClaims();init_deviceInfo();init_types21();init_types21()});var exports_auth={};__export(exports_auth,{createWebAuthnRoute:()=>createWebAuthnRoute,createSessionsRoute:()=>createSessionsRoute,createRegisterRoute:()=>createRegisterRoute,createRefreshRoute:()=>createRefreshRoute,createPasswordSetRoute:()=>createPasswordSetRoute,createPasswordResetRoute:()=>createPasswordResetRoute,createPasswordChangeRoute:()=>createPasswordChangeRoute,createMeRoute:()=>createMeRoute,createMagicLinkRoute:()=>createMagicLinkRoute,createLogoutRoute:()=>createLogoutRoute,createLoginRoute:()=>createLoginRoute,createInviteRoute:()=>createInviteRoute,createImpersonateRoute:()=>createImpersonateRoute,createHardDeleteUserRoute:()=>createHardDeleteUserRoute,createEmailVerificationRoutes:()=>createEmailVerificationRoutes,createCreateUserRoute:()=>createCreateUserRoute,createChangeUserIdRoute:()=>createChangeUserIdRoute,createAuthRoutes:()=>createAuthRoutes,createApiKeyRoutes:()=>createApiKeyRoutes});function createAuthRoutes(app,config){let{authConfig,features,helpers:helpers3}=config;if(config.oauthAccountsTable)authConfig.oauthAccountsTable=config.oauthAccountsTable;if(config.schemaTables)authConfig.schemaTables=config.schemaTables;if(config.tenantRegistry)authConfig.tenantRegistry=config.tenantRegistry;if(config.getTenantRegistry)authConfig.getTenantRegistry=config.getTenantRegistry;let buffer=authConfig.authentication?.cookieMaxAgeBufferSeconds??0,rawCookieDomain=authConfig.authentication?.cookieDomain,resolvedCookieDomainRaw=rawCookieDomain?process.env[rawCookieDomain]??rawCookieDomain:void 0,resolvedCookieDomain=resolvedCookieDomainRaw==="localhost"||resolvedCookieDomainRaw===".localhost"?void 0:resolvedCookieDomainRaw,isLocalDev=!resolvedCookieDomain,cookieConfig={accessTokenName:authConfig.authentication?.accessToken?.name||"access_token",refreshTokenName:authConfig.authentication?.refreshToken?.name||"refresh_token",sessionTokenName:authConfig.authentication?.sessionToken?.name||"session_token",accessTokenMaxAge:Math.max(0,parseTimeToSeconds2(authConfig.authentication?.accessToken?.expiresIn||"15m")-buffer),refreshTokenMaxAge:parseTimeToSeconds2(authConfig.authentication?.refreshToken?.expiresIn||"7d"),sessionTokenMaxAge:parseTimeToSeconds2(authConfig.authentication?.sessionToken?.expiresIn||"30d"),domain:resolvedCookieDomain,secure:!isLocalDev,httpOnly:!0,sameSite:"lax",path:"/"};if(authConfig.logger.info("[AUTH] Cookie config created",{accessTokenMaxAge:cookieConfig.accessTokenMaxAge,refreshTokenMaxAge:cookieConfig.refreshTokenMaxAge,sessionTokenMaxAge:cookieConfig.sessionTokenMaxAge,accessTokenExpiresIn:authConfig.authentication?.accessToken?.expiresIn,sessionTokenExpiresIn:authConfig.authentication?.sessionToken?.expiresIn}),features.login?.enabled){let loginRoutes=createLoginRoute(authConfig,features.login,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.createSession,helpers3.saveSessionToDb,cookieConfig,config.tokenResponseConfig,config.captchaService??void 0);useRoutes(app,loginRoutes)}if(features.register?.enabled){let registerRoutes=createRegisterRoute(authConfig,features.register,helpers3.sendWelcomeEmail,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.createSession,cookieConfig,config.tokenResponseConfig,config.getEmailService,config.appName,helpers3.saveSessionToDb);if(useRoutes(app,registerRoutes),features.register.emailVerification?.enabled){let emailVerificationRoutes=createEmailVerificationRoutes({authConfig,registerConfig:features.register,getEmailService:config.getEmailService,appName:config.appName});useRoutes(app,emailVerificationRoutes)}}if(features.logout?.enabled){let logoutRoutes=createLogoutRoute(authConfig,features.logout,helpers3.destroySession,helpers3.revokeSessionInDb,cookieConfig);useRoutes(app,logoutRoutes)}if(features.refresh?.enabled){let refreshRoutes=createRefreshRoute(authConfig,features.refresh,helpers3.verifyRefreshToken,helpers3.signAccessToken,helpers3.signRefreshToken,config.tokenResponseConfig,buffer,cookieConfig);useRoutes(app,refreshRoutes)}if(features.passwordReset?.enabled&&helpers3.storeResetToken&&helpers3.getResetToken&&helpers3.deleteResetToken){let passwordResetRoutes=createPasswordResetRoute(authConfig,features.passwordReset,helpers3.storeResetToken,helpers3.getResetToken,helpers3.deleteResetToken,helpers3.sendResetEmail);useRoutes(app,passwordResetRoutes)}if(features.passwordChange?.enabled){let passwordChangeRoutes=createPasswordChangeRoute(authConfig,features.passwordChange);useRoutes(app,passwordChangeRoutes)}if(features.passwordSet?.enabled){let passwordSetRoutes=createPasswordSetRoute(authConfig,features.passwordSet,helpers3.getMagicToken,helpers3.deleteMagicToken);useRoutes(app,passwordSetRoutes)}if(features.sessions?.enabled&&config.sessionsTable){let sessionsRoutes=createSessionsRoute(authConfig,features.sessions,config.sessionsTable);useRoutes(app,sessionsRoutes)}if(features.magicLink?.enabled&&helpers3.storeMagicToken&&helpers3.getMagicToken&&helpers3.deleteMagicToken){let magicLinkRoutes=createMagicLinkRoute(authConfig,features.magicLink,config.getEmailService,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.createSession,helpers3.storeMagicToken,helpers3.getMagicToken,helpers3.deleteMagicToken,config.appName,cookieConfig,helpers3.saveSessionToDb);useRoutes(app,magicLinkRoutes)}if(features.me?.enabled){let meRoutes=createMeRoute(authConfig,features.me,config.schemaTables||{},config.schemaRelations||{},config.databaseUrl);useRoutes(app,meRoutes)}if(features.invite?.enabled&&helpers3.storeMagicToken){let inviteRoutes=createInviteRoute(authConfig,features.invite,config.getEmailService,helpers3.storeMagicToken,config.appName,helpers3.getMagicToken);useRoutes(app,inviteRoutes)}if(features.captcha?.enabled&&config.captchaService){let captchaRoutes=createCaptchaRoutes({captchaService:config.captchaService,logger:authConfig.logger,basePath:features.captcha.route||"/auth/captcha"});useRoutes(app,captchaRoutes)}if(features.oauth?.enabled&&features.oauth.providers){let oauthService=new OAuthService(features.oauth,config.oauthStateStore),oauthRoutes=createOAuthRoutes(authConfig,oauthService,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.createSession,helpers3.saveSessionToDb,cookieConfig,config.tokenResponseConfig,config.getEmailService,helpers3.storeMagicToken,config.appName);useRoutes(app,oauthRoutes)}if(features.apiKeys?.enabled&&config.apiKeysTable)authConfig.apiKeysTable=config.apiKeysTable,createApiKeyRoutes(app,authConfig,features.apiKeys);if(features.webauthn?.enabled&&config.webauthnService){let webauthnRoutes=createWebAuthnRoute(authConfig,{basePath:features.webauthn.route||"/auth/webauthn",isPublic:features.webauthn.isPublic,enabled:!0},config.webauthnService,{signAccessToken:helpers3.signAccessToken,signRefreshToken:helpers3.signRefreshToken,createSession:helpers3.createSession,saveSessionToDb:helpers3.saveSessionToDb},cookieConfig);useRoutes(app,webauthnRoutes)}let checkRoutes=createCheckRoute(authConfig,{route:"/auth/check",isPublic:!1,enabled:!0});if(useRoutes(app,checkRoutes),config.admin?.impersonate?.enabled!==!1){let impersonateRoutes=createImpersonateRoute(authConfig,helpers3.signAccessToken,helpers3.signRefreshToken,helpers3.verifyRefreshToken,helpers3.createSession,helpers3.saveSessionToDb,cookieConfig);useRoutes(app,impersonateRoutes)}if(config.admin?.changeUserId?.enabled!==!1){let changeUserIdRoutes=createChangeUserIdRoute(authConfig,config.schemaName||"public");useRoutes(app,changeUserIdRoutes)}if(config.admin?.createUser?.enabled!==!1){let createUserRoutes=createCreateUserRoute(authConfig,config.admin?.createUser);useRoutes(app,createUserRoutes)}if(useRoutes(app,createPasswordAdminRoutes(authConfig,{passwordTools:config.admin?.passwordTools?.enabled===!0})),useRoutes(app,createUserStateRoutes(authConfig)),config.admin?.hardDelete?.enabled!==!1){let hardDeleteRoutes=createHardDeleteUserRoute(authConfig);useRoutes(app,hardDeleteRoutes)}return app}var init_auth=__esm(()=>{init_OAuth();init_routeMount();init_utils5();init_changeUserId();init_createUser();init_hardDeleteUser();init_impersonate();init_passwordAdmin();init_userState();init_apiKeys();init_captcha();init_check();init_emailVerification();init_invite();init_login();init_logout();init_magicLink();init_me();init_oauth();init_passwordChange();init_passwordReset();init_passwordSet();init_refresh();init_register();init_sessions();init_webauthn();init_changeUserId();init_createUser();init_hardDeleteUser();init_impersonate();init_apiKeys();init_emailVerification();init_invite();init_login();init_logout();init_magicLink();init_me();init_passwordChange();init_passwordReset();init_passwordSet();init_refresh();init_register();init_sessions();init_webauthn()});var exports_backup={};__export(exports_backup,{createBackupRoutes:()=>createBackupRoutes});function createBackupRoutes(routeConfig){let{db,logger:logger2,schemaTables,schemaName,getTenantRegistry,lock}=routeConfig,config={...DEFAULT_BACKUP_CONFIG,...routeConfig.config},basePath=config.basePath,backupLogsTable=schemaTables.backupLogs||schemaTables.backup_logs,backupService=new BackupService({db,logger:logger2,config,schemaTables,schemaName,backupLogsTable,lock});if(config.schedule.enabled)backupService.startScheduler();let guard4=createGodminGuard({db,schemaTables,logger:logger2},"backup management"),resolveTargetSchema=(targetSchema)=>{if(!targetSchema||targetSchema===schemaName)return{ok:!0,name:schemaName,tables:schemaTables};let tenantCtx=getTenantRegistry?.()?.getSchemaContext(targetSchema);if(!tenantCtx)return{ok:!1,message:`Schema not found: ${targetSchema}`};return{ok:!0,name:targetSchema,tables:tenantCtx.schemaTables}},declared=[defineRoute({method:"POST",path:basePath,handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};let body=ctx.body,target2=resolveTargetSchema(body?.schema);if(!target2.ok)return ctx.set.status=404,{success:!1,message:target2.message};let result=await backupService.createBackup("manual",userId,target2.name,target2.tables);if(result.status==="failed")return ctx.set.status=500,{success:!1,message:result.errorMessage||"Backup failed"};return{success:!0,message:"Backup created successfully",data:{id:result.id,backupName:result.backupName,schemaName:result.schemaName,tableCount:result.tableCount,rowCount:result.rowCount,sizeBytes:result.sizeBytes,status:result.status}}},body:Type.Optional(Type.Object({schema:Type.Optional(Type.String())})),detail:{tags:["Backup"],summary:"Create backup",description:"Create a new database backup. Optionally specify a schema for multi-tenant backups."}}),defineRoute({method:"GET",path:basePath,handler:async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,message:"Authentication required",data:null};let backups=await backupService.listBackups();return{success:!0,data:{items:backups,totalCount:backups.length}}},detail:{tags:["Backup"],summary:"List backups",description:"List all backup records."}}),defineRoute({method:"GET",path:`${basePath}/:id/download`,handler:async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,message:"Authentication required"};let{id}=ctx.params,filePath=await backupService.getBackupFilePath(id);if(!filePath)return ctx.set.status=404,{success:!1,message:"Backup not found"};try{let{readFile:readFile2}=await import("fs/promises"),content=await readFile2(filePath,"utf-8");return new Response(content,{headers:{"Content-Type":"application/json","Content-Disposition":`attachment; filename="${id}.json"`}})}catch{return ctx.set.status=404,{success:!1,message:"Backup file not found on disk"}}},detail:{tags:["Backup"],summary:"Download backup",description:"Download a backup file by ID."}}),defineRoute({method:"POST",path:`${basePath}/:id/restore`,handler:async(ctx)=>{let userId=ctx.request.headers.get("x-user-id");if(!userId)return ctx.set.status=401,{success:!1,message:"Authentication required"};if(!config.allowRestore)return ctx.set.status=403,{success:!1,message:"Restore is disabled in configuration"};let{id}=ctx.params,restoreBody=ctx.body,target2=resolveTargetSchema(restoreBody?.schema);if(!target2.ok)return ctx.set.status=404,{success:!1,message:target2.message};let result=await backupService.restoreFromBackup(id,userId,target2.name,target2.tables);if(!result.success)return ctx.set.status=400,result;return await logger2.audit({entityName:"backup_logs",entityId:id,operation:"RESTORE",userId,summary:`Database restored from backup ${id}`,ipAddress:ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||"unknown",userAgent:ctx.request.headers.get("user-agent")||"unknown",path:new URL(ctx.request.url).pathname,query:""}),result},detail:{tags:["Backup"],summary:"Restore from backup",description:"Restore database from a specific backup. Creates a pre-restore backup automatically."}}),defineRoute({method:"DELETE",path:`${basePath}/:id`,handler:async(ctx)=>{if(!ctx.request.headers.get("x-user-id"))return ctx.set.status=401,{success:!1,message:"Authentication required"};let{id}=ctx.params;if(!await backupService.deleteBackup(id))return ctx.set.status=404,{success:!1,message:"Backup not found"};return{success:!0,message:"Backup deleted"}},detail:{tags:["Backup"],summary:"Delete backup",description:"Delete a specific backup and its file."}})];return{routes:collectRoutes([{guards:[guard4],routes:declared}]),backupService}}var DEFAULT_BACKUP_CONFIG;var init_backup=__esm(()=>{init_esm3();init_Backup();init_routeCollector();init_adminGuard();DEFAULT_BACKUP_CONFIG={enabled:!1,basePath:"/admin/backup",storagePath:"./backups",format:"json",maxBackups:50,allowRestore:!0,excludeTables:["audit_logs","backup_logs"],schedule:{enabled:!1,cron:"0 2 * * *",retentionDays:30}}});var validateAmount=(v,field="amount",opts={})=>{if(typeof v!=="number"||!Number.isFinite(v))return{ok:!1,error:`${field} must be a finite number`};if(opts.allowZero?v<0:v<=0)return{ok:!1,error:`${field} must be ${opts.allowZero?">= 0":"> 0"}`};return{ok:!0,value:v}},isValidCurrency=(v)=>v===void 0||v===null||typeof v==="string"&&/^[A-Za-z]{3}$/.test(v);import{eq as eq65}from"drizzle-orm";var col15=(table,name2)=>table[name2],str4=(v)=>typeof v==="string"?v:null,num3=(v)=>typeof v==="number"?v:null,handleChargeRefunded=async(deps,obj)=>{let candidates=[str4(obj.id),str4(obj.payment_intent)].filter((v)=>v!==null);for(let candidate of candidates){let updated=await deps.db.update(deps.transactionsTable).set({status:"refunded",refundedAmount:num3(obj.amount_refunded)??void 0,refundedAt:new Date,statusMessage:"Refunded via Stripe webhook",updatedAt:new Date}).where(eq65(col15(deps.transactionsTable,"providerPaymentId"),candidate)).returning();if(Array.isArray(updated)&&updated.length>0)return}},handleDisputeCreated=async(deps,obj)=>{let payoutService=deps.getPayoutService?.();if(!payoutService)return;let metadata=obj.metadata??{};await payoutService.openDispute({provider:"stripe",providerDisputeId:str4(obj.id)??void 0,ownerType:str4(metadata.ownerType)==="seller"?"seller":void 0,ownerId:str4(metadata.ownerId)??void 0,amount:num3(obj.amount)??void 0,currency:str4(obj.currency)?.toUpperCase(),reason:str4(obj.reason)??void 0})},handleDisputeClosed=async(deps,obj)=>{let payoutService=deps.getPayoutService?.(),providerId=str4(obj.id);if(!payoutService||!providerId)return;await payoutService.reconcileDisputeByProvider(providerId,str4(obj.status)??"")},handlePayoutOutcome=async(deps,obj,outcome,reason)=>{let payoutService=deps.getPayoutService?.(),providerId=str4(obj.id);if(!payoutService||!providerId)return;await payoutService.reconcilePayoutByProvider(providerId,outcome,reason)},dispatch=async(deps,eventType,obj)=>{switch(eventType){case"charge.refunded":await handleChargeRefunded(deps,obj);break;case"charge.dispute.created":await handleDisputeCreated(deps,obj);break;case"charge.dispute.closed":case"charge.dispute.funds_reinstated":await handleDisputeClosed(deps,obj);break;case"payout.paid":await handlePayoutOutcome(deps,obj,"completed");break;case"payout.failed":case"payout.canceled":await handlePayoutOutcome(deps,obj,"failed",str4(obj.failure_message)??eventType);break;case"transfer.reversed":await handlePayoutOutcome(deps,obj,"failed","transfer reversed");break;default:break}},createStripeWebhookRoute=(deps)=>{return defineRoute({method:"POST",path:"/webhook",handler:async(ctx)=>{if(deps.provider.name!=="stripe")return ctx.set.status=501,{received:!1,error:"Webhooks are only supported for the Stripe provider"};if(!deps.webhookSecret)return deps.logger.error("[Payment] Webhook received but STRIPE_WEBHOOK_SECRET is not configured"),ctx.set.status=500,{received:!1,error:"Webhook secret not configured"};let rawBody=await ctx.request.text(),signature=ctx.request.headers.get("stripe-signature")??"",verified=await verifyStripeWebhook(rawBody,signature,deps.webhookSecret);if(!verified.success||!verified.event)return deps.logger.warn("[Payment] Webhook signature verification failed",{error:verified.error}),ctx.set.status=400,{received:!1,error:"Invalid signature"};let event=verified.event,eventId=str4(event.id)??"",eventType=str4(event.type)??"",obj=event.data?.object??{},idempotencyKey=`stripe:${eventId}`,inserted=await deps.db.insert(deps.webhookLogsTable).values({provider:"stripe",eventType,providerPaymentId:str4(obj.payment_intent)??str4(obj.id),rawPayload:event,processed:!1,idempotencyKey,ipAddress:ctx.request.headers.get("x-forwarded-for")??ctx.request.headers.get("x-real-ip")??null}).onConflictDoNothing().returning();if(!Array.isArray(inserted)||inserted.length===0)return{received:!0,duplicate:!0,eventType};try{return await dispatch(deps,eventType,obj),await deps.db.update(deps.webhookLogsTable).set({processed:!0,processingResult:{ok:!0},updatedAt:new Date}).where(eq65(col15(deps.webhookLogsTable,"idempotencyKey"),idempotencyKey)),deps.logger.info("[Payment] Webhook processed",{eventType,eventId}),{received:!0,eventType}}catch(err){let message=err instanceof Error?err.message:String(err);return deps.logger.error("[Payment] Webhook handler failed",{eventType,error:message}),await deps.db.update(deps.webhookLogsTable).set({errorMessage:message,updatedAt:new Date}).where(eq65(col15(deps.webhookLogsTable,"idempotencyKey"),idempotencyKey)).catch(()=>{}),ctx.set.status=500,{received:!1,error:"Handler error"}}}})};var init_webhook=__esm(()=>{init_Payment()});var exports_payment={};__export(exports_payment,{createPaymentRoutes:()=>createPaymentRoutes});import{and as and28,eq as eq66,inArray as inArray20,ne as ne4,or as or5,sql as sql13}from"drizzle-orm";var escapeHtml2=(value2)=>value2.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),generateRedirectHtml=(url,title)=>{let safeTitle=escapeHtml2(title),safeUrlAttr=escapeHtml2(url),safeUrlJs=JSON.stringify(url).replace(/</g,"\\u003c").replace(/>/g,"\\u003e");return`
|
|
526
526
|
<!DOCTYPE html>
|
|
527
527
|
<html>
|
|
528
528
|
<head>
|
|
@@ -551,7 +551,7 @@ data: ${payload}
|
|
|
551
551
|
`);throw Error(`Invalid Nucleus config:
|
|
552
552
|
${detail}`)}let sensitiveNames=resolvedForBoot.flatMap((e)=>e.columns??[]).filter((c)=>c.sensitive===!0).map((c)=>c.name);{registerSensitiveColumns(sensitiveNames);let redactUnion=[...loggingConfig?.redactKeys||[],...sensitiveColumnNames()];if(logger2.configure({redactKeys:redactUnion}),Logger.getInstance().configure({redactKeys:redactUnion}),sensitiveNames.length>0)logger2.info("[Schema] Sensitive columns registered",{columns:sensitiveNames})}}let requestLogConfig={enabled:loggingConfig?.requests?.enabled!==!1,logArrival:loggingConfig?.requests?.logArrival===!0,includeQuery:loggingConfig?.requests?.includeQuery!==!1,slowThresholdMs:loggingConfig?.requests?.slowThresholdMs??3000,excludePaths:loggingConfig?.requests?.excludePaths??["/health"]},isRequestLogExcluded=(pathname)=>requestLogConfig.excludePaths.some((p)=>p.endsWith("*")?pathname.startsWith(p.slice(0,-1)):pathname===p),envValidation=validateEnvVariables(resolvedOptions);if(!envValidation.valid){for(let error3 of envValidation.errors)logger2.error(`[CONFIG] ${error3.message}`,{field:error3.field,envName:error3.envName});throw Error("Nucleus configuration error: Missing required environment variables. Check logs for details.")}let{resolved:envResolved}=envValidation;{let secretEntries=[["accessToken",envResolved.accessTokenSecret],["refreshToken",envResolved.refreshTokenSecret],["sessionToken",envResolved.sessionTokenSecret]];for(let[name2,value2]of secretEntries)if(value2&&value2.length<32)logger2.warn(`[Security] authentication.${name2}.secret is only ${value2.length} chars \u2014 use at least ${"32"} random bytes.`);let present=secretEntries.map(([,v])=>v).filter((v)=>!!v);if(present.length>1&&new Set(present).size<present.length)logger2.warn("[Security] Two or more of the access/refresh/session token secrets are identical \u2014 use a distinct secret for each.")}let tokenNames={access_token:authentication?.accessToken?.name||"access_token",refresh_token:authentication?.refreshToken?.name||"refresh_token",session_token:authentication?.sessionToken?.name||"session_token"},csrfConfig=resolveCsrfConfig(authentication?.csrf),csrfAuthCookieNames=[tokenNames.session_token,tokenNames.access_token],targetSchemaName=database?.sharedSchema||database?.schemas?.[0]||"main",targetSchema=pgSchema2(targetSchemaName);if(envResolved.databaseUrl)await ensureDatabaseExists(envResolved.databaseUrl,logger2,envResolved.databaseAuthMode);let db=null,dbPool=null,dbAuthMode=envResolved.databaseAuthMode||"password",backgroundIntervals=[],trackInterval=(timer)=>{timer.unref?.(),backgroundIntervals.push(timer)};if(envResolved.databaseUrl){let{Pool:Pool2}=await import("pg"),poolOptions=resolveDbPoolConfig(database?.pool);if(dbAuthMode==="password")dbPool=new Pool2({connectionString:envResolved.databaseUrl,...poolOptions});else{let{getPostgresToken:getPostgresToken2}=await Promise.resolve().then(() => (init_Azure(),exports_Azure));await getPostgresToken2(),dbPool=new Pool2({connectionString:envResolved.databaseUrl,password:getPostgresToken2,ssl:{rejectUnauthorized:!0},...poolOptions}),logger2.info(`[Database] Using Entra ID auth mode: ${dbAuthMode}`)}db=drizzle2(dbPool),dbPool.on("error",(err)=>{logger2.warn("[Database] idle pool client error",{error:err instanceof Error?err.message:String(err)})})}let isMultiTenant=database?.isMultiTenant===!0,tenantRegistry=null,schemaTables={},schemaRelations={},claimsCache=null;if(config.schema){let schemasPath=__require("path").resolve(process.cwd(),config.schema),schemas=__require(schemasPath);schemaTables=schemas.createAllTablesForSchema?schemas.createAllTablesForSchema(targetSchema):{}}if(config.relations){let relationsPath=__require("path").resolve(process.cwd(),config.relations);schemaRelations=__require(relationsPath)}let secretsService=null;if(resolvedOptions.secrets?.enabled){let masterKey=resolveMasterKey(resolvedOptions.secrets.encryptionKey);if(!db)logger2.warn("[Secrets] secrets.enabled=true but no database is configured \u2014 disabled");else if(!masterKey)logger2.error("[Secrets] secrets.enabled=true but no encryption key resolved \u2014 set secrets.encryptionKey or NUCLEUS_SECRETS_KEY. Credential storage is disabled; env and literal values still work.");else if(!schemaTables[SECRETS_TABLE])logger2.error(`[Secrets] secrets.enabled=true but the "${SECRETS_TABLE}" table is missing from the generated schema \u2014 re-run schema generation. Credential storage is disabled.`);else{secretsService=new SecretsService({store:new SecretsStore({db,resolveTable:(tableName)=>schemaTables[tableName],masterKey}),logger:logger2,refreshIntervalMs:resolvedOptions.secrets.refreshIntervalMs,getRedis:()=>getRedisManager()}),logger2.info("[Secrets] Credential store enabled");try{if(await secretsService.refresh(),secretsService.isReady())logger2.info("[Secrets] Credentials preloaded for boot-time resolution",{storedCredentials:secretsService.size()})}catch(error3){logger2.warn("[Secrets] Preload failed \u2014 env and literal values still resolve",{error:error3 instanceof Error?error3.message:String(error3)})}}}let resolveCredential=(scope,key2,configValue)=>{if(secretsService)return secretsService.value(scope,key2,configValue);if(!configValue)return;let fromEnv=process.env[configValue];if(fromEnv)return fromEnv;return/^[A-Z][A-Z0-9_]{2,}$/.test(configValue)?void 0:configValue},resolveRedirectUrl=(value2)=>{if(!value2)return;let fromEnv=process.env[value2];if(fromEnv)return fromEnv;return/^[A-Z][A-Z0-9_]{2,}$/.test(value2)?void 0:value2},withResolvedRedirects=(node,keys)=>{if(!node)return node;let resolved={...node};for(let key2 of keys)if(typeof node[key2]==="string")resolved[key2]=resolveRedirectUrl(node[key2]);return resolved},trustedAppOrigins=()=>{let configured=normalizeTrustedOrigins(resolvedOptions.authentication?.trustedAppOrigins);if(!secretsService)return configured;let resolved=secretsService.listValue("authentication","trustedAppOrigins",configured);return resolved.length>0?resolved:configured},liveOAuthProviders=(resolvedProviders)=>{if(!secretsService)return resolvedProviders;let declared=resolvedOptions.authentication?.oauth?.providers??{},live={};for(let[providerName,providerConfig]of Object.entries(resolvedProviders)){let declaredConfig=declared[providerName]??{},entry={...providerConfig};for(let key2 of["clientId","clientSecret","tenantId","redirectUri"]){let declaredValue=declaredConfig[key2],bootValue=providerConfig[key2];Object.defineProperty(entry,key2,{get:()=>{let resolved=secretsService?.value(`authentication.oauth.providers.${providerName}`,key2,typeof declaredValue==="string"?declaredValue:void 0);if(resolved!==void 0)return resolved;return looksLikeEnvName(typeof bootValue==="string"?bootValue:void 0)?void 0:bootValue},enumerable:!0,configurable:!0})}live[providerName]=entry}return live},storageProvider=null;if(resolvedOptions.storage?.enabled){let storageBase=resolvedOptions.storage.basePath||"./uploads";storageProvider=createStorageProvider({provider:resolvedOptions.storage.provider,basePath:storageBase,smb:resolvedOptions.storage.smb,resolveCredential},{logger:logger2}),setStorageProvider(storageProvider)}let buildStorageProvider=(kind)=>{if(!resolvedOptions.storage?.enabled)return null;return createStorageProvider({provider:kind,basePath:resolvedOptions.storage.basePath||"./uploads",smb:resolvedOptions.storage.smb,resolveCredential:(scope,key2,configValue)=>scope==="storage"&&key2==="provider"?kind:resolveCredential(scope,key2,configValue)},{logger:logger2})};recordSwagger(config.swagger);let systemTables2=config.systemTables||[];publicRoutes=buildPublicRoutes(resolvedOptions,systemTables2,"",targetSchemaName);for(let note of unhonouredIsPublicDeclarations(resolvedOptions))logger2.warn(`[Auth] ${note}`);let unapplied=unappliedSettings(resolvedOptions,config.swagger);if(unapplied.length>0)logger2.warn(`[Config] ${unapplied.length} setting(s) are accepted but do nothing in this build:
|
|
553
553
|
${unapplied.join(`
|
|
554
|
-
`)}`);logger2.info(`[AUTH] Built ${publicRoutes.length} public routes`);let rateLimiter=null,warnedSharedRateLimitBucket=!1,peerDiversity=createPeerDiversityWatcher(),monitoringService=null,liveMonitoringService=null,lifecycleRecorder=null,LIFECYCLE_BEAT_MS=1e4,activeEmailProvider=()=>{let declared=resolveCredential("email","provider",resolvedOptions.email?.provider);if(declared==="azure"||declared==="gmail"||declared==="smtp")return emailProviderOn(declared)||resolvedOptions.email?.provider===declared?declared:null;if(emailProviderOn("azure"))return"azure";if(emailProviderOn("gmail"))return"gmail";if(emailProviderOn("smtp"))return"smtp";return null},emailProviderOn=(provider)=>{let configured=resolvedOptions.email?.[provider]?.enabled===!0;return secretsService?secretsService.flag(`email.${provider}`,"enabled",configured):configured},azureEmailCredentials=()=>{let azureConfig=resolvedOptions.email?.azure;return{enabled:!0,connectionString:resolveCredential("email.azure","connection_string",azureConfig?.connection_string)??"",senderAddress:resolveCredential("email.azure","sender_address",azureConfig?.sender_address)??"",fromName:resolveCredential("email.azure","from_name",azureConfig?.from_name)}},gmailCredentials=()=>{let gmailConfig=resolvedOptions.email?.gmail;return{enabled:!0,jsonFilePath:gmailConfig?.json_file_path,serviceAccountJson:resolveCredential("email.gmail","service_account_json",gmailConfig?.service_account_json),fromEmail:resolveCredential("email.gmail","from_email",gmailConfig?.from_email)??"",fromName:resolveCredential("email.gmail","from_name",gmailConfig?.from_name)}},smtpCredentials=()=>{let smtpConfig=resolvedOptions.email?.smtp,port=resolveCredential("email.smtp","port",smtpConfig?.port===void 0?void 0:String(smtpConfig.port)),secure=resolveCredential("email.smtp","secure",smtpConfig?.secure===void 0?void 0:String(smtpConfig.secure));return{enabled:!0,host:resolveCredential("email.smtp","host",smtpConfig?.host)??"",port:port?Number(port):void 0,secure:secure===void 0?void 0:String(secure)==="true",user:resolveCredential("email.smtp","user",smtpConfig?.user)??"",password:resolveCredential("email.smtp","password",smtpConfig?.password)??"",senderAddress:resolveCredential("email.smtp","sender_address",smtpConfig?.sender_address)??"",fromName:resolveCredential("email.smtp","from_name",smtpConfig?.from_name)}},azureService=null,gmailService=null,smtpService=null,getEmailService=()=>{let provider=activeEmailProvider();if(!provider)return null;if(provider==="azure"){if(!azureService)azureService=new AzureEmailService(azureEmailCredentials(),logger2),logger2.info("[AzureEmailService] Initialized",{available:azureService.isAvailable()});else azureService.reconfigure(azureEmailCredentials());return azureService}if(provider==="smtp"){if(!smtpService)smtpService=new SmtpEmailService(smtpCredentials(),logger2),logger2.info("[SmtpEmailService] Initialized",{available:smtpService.isAvailable()});else smtpService.applyConfig(smtpCredentials());return smtpService}if(!gmailService)gmailService=new GmailService(gmailCredentials(),logger2),logger2.info("[GmailService] Initialized",{available:gmailService.isAvailable()});else gmailService.reconfigure(gmailCredentials());return gmailService},nucleusRuntime=createNucleusRuntime({getEmailService,activeEmailProvider});if(recordRuntime(nucleusRuntime),resolvedOptions.liveMonitoring?.enabled){let liveBasePath=resolvedOptions.liveMonitoring.basePath||"/monitoring",liveStreamInterval=resolvedOptions.liveMonitoring.streamInterval||150;useRoutes(plugin,createLiveMonitoringRoutes({getService:()=>liveMonitoringService,getLifecycleRecorder:()=>lifecycleRecorder,logger:logger2,basePath:liveBasePath,streamInterval:liveStreamInterval,db,schemaTables}))}if(resolvedOptions.monitoring?.enabled&&resolvedOptions.monitoring.endpoints?.enabled){let monitoringEndpoints=resolvedOptions.monitoring.endpoints;useRoutes(plugin,createMonitoringRoutes({getService:()=>monitoringService,logger:logger2,endpoints:{enabled:!0,basePath:monitoringEndpoints.basePath||"/monitoring",allowRoles:monitoringEndpoints.allowRoles,stream:{enabled:monitoringEndpoints.stream?.enabled!==!1,path:monitoringEndpoints.stream?.path||"/stream",interval:monitoringEndpoints.stream?.interval||"5s"},snapshot:{enabled:monitoringEndpoints.snapshot?.enabled!==!1,path:monitoringEndpoints.snapshot?.path||"/snapshot"},history:{enabled:monitoringEndpoints.history?.enabled!==!1,path:monitoringEndpoints.history?.path||"/history",maxMinutes:monitoringEndpoints.history?.maxMinutes||60},alerts:{enabled:monitoringEndpoints.alerts?.enabled!==!1,path:monitoringEndpoints.alerts?.path||"/alerts"}},db,schemaTables}))}if(serverLogBuffer)useRoutes(plugin,createServerLogRoutes({buffer:serverLogBuffer,logger:logger2,basePath:serverLogsConfig?.basePath||resolvedOptions.monitoring?.endpoints?.basePath||"/monitoring",path:serverLogsConfig?.path||"/server-logs",allowRoles:serverLogsConfig?.allowRoles,streamEnabled:serverLogsConfig?.stream!==!1,clearEnabled:serverLogsConfig?.allowClear!==!1,db,schemaTables}));let bootStep=async(name2,run)=>{try{return await run()}catch(error3){logger2.error(`[Boot] Step "${name2}" failed \u2014 continuing in a degraded state rather than crashing`,{error:error3 instanceof Error?error3.message:String(error3)});return}},inboundGuard=createInboundGuard({maxRequestBodyBytes:resolvedOptions.security?.maxRequestBodyBytes});recordBootStep(async()=>{await bootStep("redis",()=>initiateRedisManager(resolvedOptions));let redis=getRedisManager();if(redis&&resolvedOptions.configManagement?.enabled)try{let{loadOverridesFromRedis:loadOverridesFromRedis2}=await Promise.resolve().then(() => (init_helpers4(),exports_helpers)),redisAdapter={read:async(key2)=>{let r=await redis.read(key2);return{success:r.success,data:r.success?r.data:null}}},{applied,ignored}=await loadOverridesFromRedis2(redisAdapter,resolvedOptions.appId||"nucleus",resolvedOptions);if(applied.length>0)logger2.info(`[ConfigManagement] Loaded ${applied.length} override(s) from Redis`,{sections:applied});if(ignored.length>0)logger2.warn(`[ConfigManagement] Ignored ${ignored.length} Redis override(s) naming no config section`,{sections:ignored})}catch(err){logger2.warn("[ConfigManagement] Failed to load overrides from Redis",{error:err instanceof Error?err.message:String(err)})}if(redis&&resolvedOptions.rateLimit?.enabled!==!1)rateLimiter=new RateLimiter({redis,logger:logger2,config:resolvedOptions.rateLimit||{}}),logger2.info(`[RateLimit] Enabled with strategy: ${resolvedOptions.rateLimit?.strategy||"sliding-window"}`);{let channels=resolvedOptions.notification?.channels;if(channels?.telegram?.enabled&&(!channels.telegram.botToken||!channels.telegram.chatId))logger2.warn("[Notification] telegram channel is enabled but botToken/chatId is missing \u2014 telegram deliveries will be skipped");if(channels?.webhook?.enabled&&!channels.webhook.url)logger2.warn("[Notification] webhook channel is enabled but url is missing \u2014 webhook deliveries will be skipped")}if(redis&&resolvedOptions.monitoring?.enabled){let monitoringDb=db,monitoringMetricsTable=schemaTables.monitoringMetrics,monitoringPersistenceEnabled=resolvedOptions.monitoring.persistence?.enabled!==!1,monitoringRetentionDays=resolvedOptions.monitoring.persistence?.retentionDays??30,lastMetricsCleanupAt=0,monitoringDbQuery=monitoringDb?async(sqlText)=>{return(await monitoringDb.execute(sql15.raw(sqlText))).rows}:void 0,monitoringLoadPeaks=monitoringDb&&monitoringPersistenceEnabled&&monitoringMetricsTable?async()=>{let t=monitoringMetricsTable;return(await monitoringDb.select({metricName:t.metricName,value:t.value,recordedAt:t.recordedAt,tags:t.tags}).from(t).where(eq70(t.metricType,"peak")).orderBy(desc7(t.value))).map((r)=>({metricName:String(r.metricName),value:Number(r.value??0),at:r.recordedAt?new Date(r.recordedAt).getTime():0,context:r.tags??void 0}))}:void 0;if(monitoringPersistenceEnabled&&monitoringDb&&!monitoringMetricsTable)logger2.warn("[Monitoring] monitoring.persistence is enabled but the monitoring_metrics table is missing from the generated schema \u2014 re-run nucleus-generate to add it");let monitoringFlushToDb=monitoringDb&&monitoringPersistenceEnabled&&monitoringMetricsTable?async(metrics)=>{if(metrics.length===0)return;let metricsTable=monitoringMetricsTable;await monitoringDb.insert(metricsTable).values(metrics.map((m)=>({metricType:m.metricType,metricName:m.metricName,value:m.value,tags:m.tags??null,recordedAt:new Date(m.timestamp)})));let nowMs=Date.now();if(nowMs-lastMetricsCleanupAt>86400000){lastMetricsCleanupAt=nowMs;let cutoff=new Date(nowMs-monitoringRetentionDays*24*60*60*1000);await monitoringDb.delete(metricsTable).where(and30(lt3(metricsTable.recordedAt,cutoff),ne5(metricsTable.metricType,"peak")))}}:void 0;monitoringService=new MonitoringService({redis,logger:logger2,getEmailService,config:resolvedOptions.monitoring,appId:resolvedOptions.appId,dbQuery:monitoringDbQuery,flushToDb:monitoringFlushToDb,loadPeaks:monitoringLoadPeaks}),monitoringService.start(),logger2.info("[Monitoring] Service started")}if(resolvedOptions.liveMonitoring?.enabled)liveMonitoringService=new LiveMonitoringService(resolvedOptions.liveMonitoring),liveMonitoringService.start(),logger2.info("[LiveMonitoring] Service started");let lifecycleRedis=getRedisManager()?.getDirectClient?.();if(lifecycleRedis){lifecycleRecorder=new LifecycleRecorder({backend:redisLifecycleBackend(lifecycleRedis),labels:{...process.env.HOSTNAME?{host:process.env.HOSTNAME}:{},...process.env.APP_VERSION?{version:process.env.APP_VERSION}:{}},logger:logger2}),lifecycleRecorder.claim();let beat=setInterval(()=>{(async()=>{let memory=(await monitoringService?.getLatestSnapshot?.())?.system?.memory;await lifecycleRecorder?.touch(memory?{rss:memory.rss??0,heapUsed:memory.heapUsed,external:memory.external??0,total:memory.total,usagePercent:memory.usagePercent,scope:memory.scope}:void 0)})()},LIFECYCLE_BEAT_MS);backgroundIntervals.push(beat),process.on("uncaughtException",(error3)=>{lifecycleRecorder?.recordFatal(error3,"uncaughtException"),logger2.error("[Lifecycle] Uncaught exception",error3)}),process.on("unhandledRejection",(reason)=>{lifecycleRecorder?.recordFatal(reason,"unhandledRejection"),logger2.error("[Lifecycle] Unhandled rejection",reason)})}let isConsumerModeOnStart=authentication?.mode==="consumer",consumerAllowedTableKeys=isConsumerModeOnStart&&entities?new Set(entities.map((e)=>e.table_name.replace(/_([a-z])/g,(_,c)=>c.toUpperCase()))):null;if(consumerAllowedTableKeys){let opts=resolvedOptions,verificationEnabled=opts.verification?.enabled===!0,notificationEnabled=opts.notification?.enabled===!0,auditEnabled=opts.audit?.enabled===!0,chatEnabled=opts.chat?.enabled===!0,storageEnabled=opts.storage?.enabled===!0,paymentEnabled=opts.payment?.enabled===!0,backupEnabled=opts.backup?.enabled===!0,monitoringPersistenceOn=resolvedOptions.monitoring?.enabled===!0&&resolvedOptions.monitoring?.persistence?.enabled!==!1,featureEnabled={verification:verificationEnabled,notification:notificationEnabled,audit:auditEnabled,chat:chatEnabled,storage:storageEnabled,payment:paymentEnabled,backup:backupEnabled,monitoring:monitoringPersistenceOn,secrets:resolvedOptions.secrets?.enabled===!0,domains:resolvedOptions.domains?.enabled===!0,"multi-tenant":isMultiTenant};for(let sysTable of SYSTEM_TABLES)if(sysTable.feature_set.some((f)=>{if(f==="authentication"||f==="authorization")return!1;if(!(f in featureEnabled))return logger2.warn(`[Schema] Consumer mode has no rule for feature "${f}" (table "${sysTable.table_name}") \u2014 `+"its table will NOT be synced. Add it to featureEnabled in Nucleus/index.ts."),!1;return featureEnabled[f]===!0})){let camelKey=sysTable.table_name.replace(/_([a-z])/g,(_,c)=>c.toUpperCase());consumerAllowedTableKeys.add(camelKey)}}if(db&&config.schema){let schemas=await import(__require("path").resolve(process.cwd(),config.schema)),auditLogsTable=schemaTables.auditLogs||schemas.auditLogs;if(audit?.enabled&&auditLogsTable)logger2.addAuditTransport(new DatabaseAuditTransport({db,table:auditLogsTable,enabled:!0,dedup:audit.dedup}));let{ensureSchemaExists:ensureSchemaExists2,applySchemaPush:applySchemaPush2}=await Promise.resolve().then(() => (init_schema(),exports_schema)),{reconcileMissingColumns:reconcileMissingColumns2,expectedFromTables:expectedFromTables2,readActualSchema:readActualSchema2,undeclaredTables:undeclaredTables2}=await Promise.resolve().then(() => (init_schemaReconcile(),exports_schemaReconcile));try{logger2.info(`Syncing schema to database (target: ${targetSchemaName})...`),await ensureSchemaExists2(db,targetSchemaName);let filteredTables={};try{filteredTables=Object.fromEntries(Object.entries(schemaTables).filter(([key2,v])=>{if(v===void 0||v===null)return!1;if(consumerAllowedTableKeys&&!consumerAllowedTableKeys.has(key2))return!1;if(typeof v==="object"&&v!==null)return Object.getOwnPropertySymbols(v).length>0||v._!==void 0;return!1}));let tableNames=Object.keys(filteredTables);if(logger2.info("[Schema] Tables to sync:",{tables:tableNames,count:tableNames.length,mode:isConsumerModeOnStart?"consumer":"full"}),!isConsumerModeOnStart){let usersTableDef=filteredTables.users;if(usersTableDef){let columnSymbols=Object.getOwnPropertyNames(usersTableDef).filter((k)=>!k.startsWith("_"));logger2.info("[Schema] Users table columns:",{columns:columnSymbols})}}let realExit=process.exit,push;try{process.exit=(code)=>{throw Error(`drizzle-kit called process.exit(${code??0}) during pushSchema \u2014 `+"suppressed so the app can keep booting")};let excluded=await(async()=>{try{let actual=await readActualSchema2((statement)=>db.execute(sql15.raw(statement)),targetSchemaName);return undeclaredTables2(expectedFromTables2(filteredTables),actual)}catch{return[]}})();if(excluded.length>0)logger2.info(`[Schema] Excluding tables the model does not declare, so the push is not asked to resolve a rename it cannot: ${excluded.join(", ")}`);let timeoutMs=database?.schemaPushTimeoutMs??120000;push=await withDeadline(pushSchema({schema:targetSchema,...filteredTables},db,[targetSchemaName],excluded.length>0?excluded.map((name2)=>`!${name2}`):void 0),timeoutMs,`pushSchema did not finish within ${timeoutMs}ms. drizzle-kit most likely hit its `+"interactive rename prompt, which cannot be answered without a TTY \u2014 it appears "+"when a push adds a new table while another table exists in the database but not in the schema. Drop the stale table, or split the change across two deploys.")}finally{process.exit=realExit}if(await applySchemaPush2(push,{schemaName:targetSchemaName,allowDataLoss:database?.allowDataLoss===!0,logger:logger2,execute:(statement)=>db.execute(sql15.raw(statement))}))logger2.info("[Schema] pushSchema completed successfully")}catch(pushError){let msg=pushError instanceof Error?pushError.message:String(pushError),repair=await reconcileMissingColumns2({db,schema:targetSchemaName,tables:filteredTables,logger:logger2,schemaObject:targetSchema});if(!repair||repair.applied>0||repair.plan.createdTables.length>0||repair.plan.missingTables.length>0||repair.plan.unsafe.length>0)logger2.error(`[Schema] pushSchema applied NOTHING: ${msg}`);else logger2.info(`[Schema] pushSchema applied nothing, and nothing was needed \u2014 the database already matches the model. (${msg})`)}logger2.info("[Schema] Schema sync completed",{schema:targetSchemaName})}catch(error3){logger2.error("[Schema] Schema sync failed",error3,{schema:targetSchemaName})}try{let{relaxSessionExpiryIfNever:relaxSessionExpiryIfNever2}=await Promise.resolve().then(() => (init_relaxSessionExpiry(),exports_relaxSessionExpiry)),{sql:sql16}=await import("drizzle-orm");await relaxSessionExpiryIfNever2({db,sql:sql16,schemaName:targetSchemaName,lifetimeSeconds:lifetimeSeconds(authentication?.sessionToken?.expiresIn,2592000),logger:logger2})}catch(error3){logger2.warn("[Schema] Session expiry relaxation skipped",{error:String(error3)})}if(secretsService)try{await secretsService.start(),logger2.info("[Secrets] Credential store ready",{storedCredentials:secretsService.size()})}catch(error3){logger2.error("[Secrets] Credential store failed to start \u2014 env and literal values still resolve",{error:error3 instanceof Error?error3.message:String(error3)})}if(logger2.info("[Database] Connection established"),await bootStep("multi-tenant schemas",async()=>{if(isMultiTenant&&db&&config.schema){let schemasForTenant={};try{let schemaPath=__require("path").resolve(process.cwd(),config.schema);logger2.info("[MultiTenant] Loading schema for tenant registry",{schemaPath}),schemasForTenant=await import(schemaPath),logger2.info("[MultiTenant] Schema loaded",{keys:Object.keys(schemasForTenant).slice(0,10),hasCreateAll:!!schemasForTenant.createAllTablesForSchema})}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.error("[MultiTenant] Failed to load schema for tenant registry",{error:msg})}let createAllFn=schemasForTenant.createAllTablesForSchema;if(createAllFn){let idpUrl=isConsumerModeOnStart?authentication?.idpUrl?String(process.env[authentication.idpUrl]||authentication.idpUrl):void 0:void 0;if(tenantRegistry=new TenantRegistry({db,logger:logger2,mainSchemaName:targetSchemaName,mainSchemaTables:schemaTables,mainSchemaRelations:schemaRelations,createAllTablesForSchema:createAllFn,createAllRelationsForSchema:schemasForTenant.createAllRelationsForSchema,appId:resolvedOptions.appId,authMode:authentication?.mode,tenantResolution:database?.tenantResolution||"both",tenantHeader:database?.tenantHeader||"x-tenant-id",redisCacheTtlSeconds:300,defaultTrustedSources:database?.defaultTrustedSources,idpUrl,allowDataLoss:database?.allowDataLoss===!0,onTenantProvisioned:resolvedOptions.authorization?.enabled&&!isConsumerModeOnStart?async(context)=>{let authConfig={...DEFAULT_AUTHORIZATION_CONFIG,...resolvedOptions.authorization};if(authConfig.autoSeedClaims&&db){let claimEntities=mergeEntitiesByName([...extractSchemaTableEntities(context.schemaTables),...SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),...effectiveConfigEntities(resolvedOptions.entities||[]),...config.systemTables||[],...resolvedOptions.authorization?.externalEntities||[]]);await seedClaims(db,context.schemaTables,context.schemaRelations,claimEntities,authConfig,logger2)}let seedConfig=resolvedOptions.authorization?.seed;if(seedConfig&&db){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));await runSeed2(db,context.schemaTables,seedConfig,logger2)}logger2.info(`[Authorization] New tenant schema seeded: ${context.schemaName}`)}:void 0}),isConsumerModeOnStart&&idpUrl){await tenantRegistry.initializeFromIdp(),logger2.info("[MultiTenant] Consumer mode: tenants fetched from IDP");let tenantSyncTimer=setInterval(()=>{tenantRegistry?.syncFromIdp().then((result)=>{if(result.added.length>0||result.removed.length>0)logger2.info(`[MultiTenant] Tenant sync: +${result.added.length} / -${result.removed.length} (total ${result.total})`)}).catch((err)=>{let msg=err instanceof Error?err.message:String(err);logger2.warn(`[MultiTenant] Tenant sync failed: ${msg}`)})},60000);trackInterval(tenantSyncTimer)}else await tenantRegistry.initialize();for(let schemaName of tenantRegistry.getAllSchemaNames()){if(schemaName===targetSchemaName)continue;let ctx=tenantRegistry.getSchemaContext(schemaName);if(ctx){await ensureSchemaExists2(db,schemaName);try{let tenantFilteredTables=Object.fromEntries(Object.entries(ctx.schemaTables).filter(([key2,v])=>{if(v===void 0||v===null)return!1;if(consumerAllowedTableKeys&&!consumerAllowedTableKeys.has(key2))return!1;if(typeof v==="object"&&v!==null)return Object.getOwnPropertySymbols(v).length>0||v._!==void 0;return!1})),tenantSchema=pgSchema2(schemaName),tenantPush=await pushSchema({schema:tenantSchema,...tenantFilteredTables},db,[schemaName]);if(await applySchemaPush2(tenantPush,{schemaName,allowDataLoss:database?.allowDataLoss===!0,logger:logger2,execute:(statement)=>db.execute(sql15.raw(statement))}))logger2.info(`[Schema] Tenant schema synced: ${schemaName}`)}catch(tenantPushError){let msg=tenantPushError instanceof Error?tenantPushError.message:String(tenantPushError);logger2.warn(`[Schema] Tenant schema sync warning for ${schemaName}: ${msg}`)}}}logger2.info(`[MultiTenant] Registry initialized with ${tenantRegistry.getAllSchemaNames().length} schemas`),logger2.info("[MultiTenant] Tenant registry ready, routes were pre-registered")}}}),resolvedOptions.authorization?.enabled&&!isConsumerModeOnStart){let authConfig={...DEFAULT_AUTHORIZATION_CONFIG,...resolvedOptions.authorization,godminEmail:resolveConfigCredential(resolvedOptions.authorization?.godminEmail),godminPassword:resolveConfigCredential(resolvedOptions.authorization?.godminPassword)};if(authConfig.autoSeedClaims){let schemaEntities=extractSchemaTableEntities(schemaTables),systemEntities=SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),configEntities=effectiveConfigEntities(resolvedOptions.entities||[]),externalEntities=resolvedOptions.authorization?.externalEntities||[],claimEntities=mergeEntitiesByName([...schemaEntities,...configEntities,...systemEntities,...config.systemTables||[],...externalEntities]);logger2.info("[Authorization] Seeding claims...",{schemaEntities:schemaEntities.length,systemEntities:systemEntities.length,configEntities:configEntities.length,externalEntities:externalEntities.length,totalEntities:claimEntities.length}),await seedClaims(db,schemaTables,schemaRelations,claimEntities,authConfig,logger2)}let discoveryConfig=resolvedOptions.authorization?.endpointDiscovery;if(discoveryConfig?.enabled&&(discoveryConfig.runOnBoot??!0)&&db)try{let{runEndpointDiscovery:runEndpointDiscovery2}=await Promise.resolve().then(() => (init_seed(),exports_seed)),discoveryResult=await runEndpointDiscovery2(db,schemaTables,discoveryConfig,logger2);logger2.info("[Authorization] Endpoint discovery completed",{services:discoveryResult.services})}catch(discoveryErr){logger2.error("[Authorization] Endpoint discovery failed",{error:discoveryErr instanceof Error?discoveryErr.message:String(discoveryErr)})}if(authConfig.godminEmail&&authConfig.godminPassword)logger2.info("[Authorization] Setting up godmin..."),await setupGodmin(db,schemaTables,authConfig,logger2);let seedConfig=resolvedOptions.authorization?.seed;if(seedConfig){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));logger2.info("[Authorization] Running custom seed...");let seedResult=await bootStep("authorization.seed",()=>runSeed2(db,schemaTables,seedConfig,logger2));if(seedResult)logger2.info("[Authorization] Custom seed completed",{rolesCreated:seedResult.rolesCreated,rolesExisting:seedResult.rolesExisting,claimsCreated:seedResult.claimsCreated,claimsExisting:seedResult.claimsExisting,assignmentsCreated:seedResult.assignmentsCreated,assignmentsExisting:seedResult.assignmentsExisting,assignmentsUpdated:seedResult.assignmentsUpdated})}let claimGuardsCfg=resolvedOptions.authorization?.claimGuards;if(claimGuardsCfg?.length){let{seedClaimGuards:seedClaimGuards2}=await Promise.resolve().then(() => (init_ClaimGuard(),exports_ClaimGuard));await bootStep("authorization.claimGuards",()=>seedClaimGuards2(db,schemaTables,claimGuardsCfg,logger2))}let jwtClaimsMode=resolvedOptions.authorization?.jwtClaimsMode||"embed",claimsCacheRedis=getRedisManager();if(jwtClaimsMode==="resolve"&&db&&claimsCacheRedis){let{ClaimsCache:ClaimsCache3}=await Promise.resolve().then(() => (init_ClaimsCache(),exports_ClaimsCache));claimsCache=new ClaimsCache3({prefix:resolvedOptions.authorization?.claimsCachePrefix||"nucleus:claims",redis:{get:async(key2)=>{let r=await claimsCacheRedis.read(key2);return r.success?r.data:null},set:async(key2,value2)=>{await claimsCacheRedis.create(key2,value2)},delete:async(key2)=>{await claimsCacheRedis.remove(key2)}},db,schemaTables,logger:logger2});let cacheInstance=claimsCache,cacheResult=await bootStep("authorization.claimsCache",()=>cacheInstance.buildCache());if(cacheResult)logger2.info("[Authorization] Claims cache built (resolve mode)",{version:cacheResult.version,roleCount:cacheResult.roleCount,totalMappings:cacheResult.totalMappings})}else if(jwtClaimsMode==="resolve"&&!claimsCacheRedis)logger2.warn("[Authorization] jwtClaimsMode=resolve requires Redis. Falling back to embed mode.");if(logger2.info("[Authorization] Enabled"),isMultiTenant&&tenantRegistry){let tenantSchemas=tenantRegistry.getAllSchemaNames().filter((name2)=>name2!==targetSchemaName);for(let tenantSchemaName of tenantSchemas){let tenantCtx=tenantRegistry.getSchemaContext(tenantSchemaName);if(!tenantCtx)continue;try{if(authConfig.autoSeedClaims){let tenantSchemaEntities=extractSchemaTableEntities(tenantCtx.schemaTables),tenantClaimEntities=mergeEntitiesByName([...tenantSchemaEntities,...SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),...effectiveConfigEntities(resolvedOptions.entities||[]),...config.systemTables||[],...resolvedOptions.authorization?.externalEntities||[]]);await seedClaims(db,tenantCtx.schemaTables,tenantCtx.schemaRelations,tenantClaimEntities,authConfig,logger2)}if(tenantCtx.tenant?.godAdminEmail&&authConfig.godminPassword)await setupGodmin(db,tenantCtx.schemaTables,{...authConfig,godminEmail:tenantCtx.tenant.godAdminEmail},logger2);if(seedConfig){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));await runSeed2(db,tenantCtx.schemaTables,seedConfig,logger2)}logger2.info(`[Authorization] Tenant schema seeded: ${tenantSchemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.warn(`[Authorization] Failed to seed tenant ${tenantSchemaName}: ${msg}`)}}logger2.info(`[Authorization] Multi-tenant seeding complete for ${tenantSchemas.length} schemas`)}}let sessionsTableRef=schemaTables.userSessions;if(!isConsumerModeOnStart&&sessionsTableRef&&resolvedOptions.authentication?.sessions?.enabled){let{lt:lt4}=await import("drizzle-orm"),expiredCount=await bootStep("auth.expiredSessionCleanup",()=>db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and30(eq70(sessionsTableRef.isActive,!0),lt4(sessionsTableRef.expiresAt,new Date))));if(expiredCount!==void 0)logger2.info("[AUTH] Expired sessions cleanup completed",{expiredCount});let sessionCleanupInterval=setInterval(async()=>{try{await db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and30(eq70(sessionsTableRef.isActive,!0),lt4(sessionsTableRef.expiresAt,new Date)));let approvalTtlMs=86400000,approvalCutoff=new Date(Date.now()-approvalTtlMs);await db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"approval_token_expired",approvalStatus:"rejected",approvalToken:null}).where(and30(eq70(sessionsTableRef.approvalStatus,"pending"),lt4(sessionsTableRef.approvalRequestedAt,approvalCutoff)))}catch(err){logger2.warn("[AUTH] Session cleanup failed",{error:err})}},3600000);trackInterval(sessionCleanupInterval)}if(isMultiTenant&&tenantRegistry&&resolvedOptions.authentication?.sessions?.enabled){let{lt:lt4}=await import("drizzle-orm"),tenantSchemaNames=tenantRegistry.getAllSchemaNames().filter((name2)=>name2!==targetSchemaName);for(let tenantSchemaName of tenantSchemaNames){let tenantCtx=tenantRegistry.getSchemaContext(tenantSchemaName);if(!tenantCtx)continue;let tenantSessionsTable=tenantCtx.schemaTables.userSessions||tenantCtx.schemaTables.user_sessions||tenantCtx.schemaTables.sessions;if(!tenantSessionsTable)continue;try{await db.update(tenantSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and30(eq70(tenantSessionsTable.isActive,!0),lt4(tenantSessionsTable.expiresAt,new Date))),logger2.info(`[AUTH] Tenant session cleanup completed: ${tenantSchemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.warn(`[AUTH] Tenant session cleanup failed for ${tenantSchemaName}: ${msg}`)}}}}});let authMiddleware=async({request,set:set2,server})=>{let refusal=inboundGuard({request,set:set2,body:void 0,params:{},query:{}});if(refusal!==void 0)return refusal;let requestStartTime=Date.now(),requestSchemaTables=schemaTables;if(tenantRegistry){let tenantVettedClientIp=resolveClientIp(server?.requestIP?.(request)?.address??null,request.headers.get("x-forwarded-for")??request.headers.get("x-real-ip"),resolvedOptions.rateLimit?.trustedProxies??[]),tenantResult=tenantRegistry.resolveFromRequest(request,tenantVettedClientIp);if(tenantResult.resolved)requestSchemaTables=tenantResult.context.schemaTables,request.headers.set("x-tenant-schema",tenantResult.context.schemaName);else if(new URL(request.url).pathname!=="/health")return set2.status=tenantResult.statusCode,Response.json(withEnvelopeFlags({isSuccess:!1,message:tenantResult.error,status:tenantResult.statusCode,errors:[{message:tenantResult.error}],data:null}))}request.headers.set("x-request-start-time",String(requestStartTime));let requestId=randomUUID11();if(request.headers.set("x-request-id",requestId),set2.headers["x-request-id"]=requestId,resolvedOptions.security?.disableDefaultHeaders!==!0){set2.headers["X-Content-Type-Options"]="nosniff",set2.headers["X-Frame-Options"]="SAMEORIGIN",set2.headers["Referrer-Policy"]="strict-origin-when-cross-origin";let hstsMaxAge=resolvedOptions.security?.hstsMaxAge??15552000;if(hstsMaxAge>0)set2.headers["Strict-Transport-Security"]=`max-age=${hstsMaxAge}; includeSubDomains`}let url=new URL(request.url),pathname=url.pathname,method=request.method,query=url.search;if(csrfConfig.enabled){let csrfSecure=request.headers.get("x-forwarded-proto")==="https"||url.protocol==="https:"?"; Secure":"",issueCsrfCookie=()=>`${csrfConfig.cookieName}=${randomUUID11()}; Path=/; SameSite=Lax${csrfSecure}`,csrfCookies=parseCookies(request.headers.get("cookie"));if(requiresCsrf({method,cookies:csrfCookies,hasAuthorizationHeader:!!request.headers.get("authorization"),authCookieNames:csrfAuthCookieNames})&&!csrfTokenMatches(csrfCookies[csrfConfig.cookieName],request.headers.get(csrfConfig.headerName)))return set2.headers["Set-Cookie"]=issueCsrfCookie(),set2.status=403,Response.json(withEnvelopeFlags({isSuccess:!1,message:"CSRF token missing or invalid",status:403,errors:[{message:"CSRF token missing or invalid"}],data:null}));else if(!isStateChanging(method)&&!csrfCookies[csrfConfig.cookieName])set2.headers["Set-Cookie"]=issueCsrfCookie()}let socketIp=server?.requestIP?.(request)?.address??null,clientIp=resolveClientIp(socketIp,request.headers.get("x-forwarded-for")??request.headers.get("x-real-ip"),resolvedOptions.rateLimit?.trustedProxies??[]);request.headers.set("x-client-ip",clientIp);let userAgent=request.headers.get("user-agent")||"unknown";if(requestLogConfig.enabled&&requestLogConfig.logArrival&&!isRequestLogExcluded(pathname))logger2.log("debug",`\u2192 ${method} ${pathname}`,{requestId,method,path:pathname,query:requestLogConfig.includeQuery&&query?query:void 0,ip:clientIp,tenant:request.headers.get("x-tenant-schema")||void 0},void 0,void 0,"middleware.request");let tokens,parsedBody={},rawBodyText="";if(request.method!=="GET"&&request.method!=="HEAD")try{rawBodyText=await request.clone().text();let parsed=rawBodyText?JSON.parse(rawBodyText):{};parsedBody=parsed&&typeof parsed==="object"?parsed:{}}catch{parsedBody={}}let auditPayload=audit?.enabled?{id:randomUUID11(),user_id:"unknown",entity_name:pathname.split("/").filter(Boolean)[0]||"root",entity_id:null,operation_type:method,summary:"",old_values:{},new_values:parsedBody,ip_address:clientIp,user_agent:userAgent,timestamp:new Date().toISOString(),path:pathname,query}:null,isPublic=isPublicRoute(publicRoutes,pathname,method,{headers:request.headers,credentialed:()=>{let presented=parseTokenValuesFromHeaders(request.headers,tokenNames);return!!(presented.session_token||presented.access_token)}}),rateLimiterUserBudgetPending=!1,refuseRateLimited=(budget,retryAfter,subject)=>{if(set2.status=429,retryAfter)set2.headers["Retry-After"]=String(retryAfter);if(logger2.warn(`[RateLimit] Blocked ${pathname}: the ${budget} budget is spent (${budget==="address"?clientIp:subject||clientIp})`+(retryAfter?`, retry after ${retryAfter}s`:"")),monitoringService)monitoringService.recordRateLimitBlock();return new Response(JSON.stringify({isSuccess:!1,success:!1,message:"Too Many Requests",status:429,errors:[{message:"Too Many Requests"}],data:null,retryAfter}),{status:429,headers:{"Content-Type":"application/json"}})};if(rateLimiter){let routeCategory=isPublic?"public":"private",authType=resolveAuthType(pathname,resolvedOptions.authentication),category=authType?"auth":routeCategory,sharedPeer=!warnedSharedRateLimitBucket&&(resolvedOptions.rateLimit?.trustedProxies??[]).length===0&&(isNonDiscriminatingPeer(clientIp)?clientIp:peerDiversity.observe(clientIp));if(sharedPeer)warnedSharedRateLimitBucket=!0,logger2.warn(`[RateLimit] Every request so far has arrived from ${sharedPeer}, which cannot tell callers apart: every user shares ONE rate-limit bucket and one person can exhaust it for everybody. Set rateLimit.trustedProxies to the proxy address so X-Forwarded-For is honored, or raise rateLimit.privateRoutes/publicRoutes/authRoutes to values shared traffic cannot reach.`);rateLimiterUserBudgetPending=category==="private";let attempted=authType?readAttemptedIdentity(parsedBody,rawBodyText,request.headers.get("content-type")):void 0;if(authType&&!attempted&&(request.headers.get("content-type")||"").toLowerCase().includes("multipart/form-data"))try{let value2=(await request.clone().formData()).get("email");if(typeof value2==="string"&&value2.trim())attempted=value2}catch{}let rateLimitResult=await rateLimiter.check({ip:clientIp,endpoint:pathname,category,authType,identityResolved:authType?!!attempted:void 0}),limiter=rateLimiter,tightest=rateLimitResult,applyRateLimitHeaders=(result)=>{if(result.remaining>=0&&(tightest.remaining<0||result.remaining<tightest.remaining))tightest=result;for(let[key2,value2]of Object.entries(limiter.getHeaders(tightest)))set2.headers[key2]=value2};if(applyRateLimitHeaders(rateLimitResult),!rateLimitResult.allowed)return refuseRateLimited("address",rateLimitResult.retryAfter);if(attempted){let perIdentity=await rateLimiter.check({ip:clientIp,endpoint:pathname,category,authType,identity:attempted});if(applyRateLimitHeaders(perIdentity),!perIdentity.allowed)return refuseRateLimited("account",perIdentity.retryAfter,"the account being attempted")}}if(pathname==="/health"||pathname==="/health/ready")return;if(authentication?.enabled&&!isPublic){let apiKeyRaw=extractApiKeyFromHeader(request.headers),apiKeysTableRef=requestSchemaTables.apiKeys;if(apiKeyRaw&&authentication.apiKeys?.enabled&&apiKeysTableRef&&db){let keyHash=hashApiKey(apiKeyRaw),apiKeyRecord=(await db.select().from(apiKeysTableRef).where(eq70(apiKeysTableRef.keyHash,keyHash)).limit(1))[0];if(!apiKeyRecord)return set2.status=401,logger2.traceSync({message:"Invalid API key",level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,"Invalid API key")}),Error("Invalid API key");let validation=validateApiKeyRecord(apiKeyRecord);if(!validation.valid)return set2.status=401,logger2.traceSync({message:`API key rejected: ${validation.reason}`,level:"warn",context:{path:pathname,method,keyId:apiKeyRecord.id},audit:toAudit(auditPayload,`API key rejected: ${validation.reason}`)}),Error(validation.reason);let apiKeyUserId=apiKeyRecord.userId,apiKeyUserData;{let ksTable=requestSchemaTables.users;if(ksTable&&db){apiKeyUserData=(await db.select().from(ksTable).where(eq70(ksTable.id,apiKeyUserId)).limit(1))[0];let{evaluateAccountState:evaluateAccountState2}=await Promise.resolve().then(() => exports_accountState),ksState=apiKeyUserData?evaluateAccountState2(apiKeyUserData):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!ksState.allowed)return set2.status=401,logger2.traceSync({message:`API key rejected: account ${ksState.reason}`,level:"warn",context:{path:pathname,method,keyId:apiKeyRecord.id},audit:toAudit(auditPayload,`API key rejected: account ${ksState.reason}`,{userId:apiKeyUserId})}),Error(ksState.message)}}let keyAllowedRoles=apiKeyRecord.allowedRoles||[],keyAllowedClaims=apiKeyRecord.allowedClaims||[],effectiveRoles=keyAllowedRoles,effectiveClaims=keyAllowedClaims,apiKeyClaimScopes={},userRolesTable=requestSchemaTables.userRoles,rolesTable=requestSchemaTables.roles,roleClaimsTable=requestSchemaTables.roleClaims,claimsTable=requestSchemaTables.claims;if(userRolesTable&&rolesTable){let currentUserRoles=(await db.select({name:rolesTable.name}).from(userRolesTable).innerJoin(rolesTable,eq70(rolesTable.id,userRolesTable.roleId)).where(eq70(userRolesTable.userId,apiKeyUserId))).map((r)=>r.name).filter((n)=>n!==void 0);effectiveRoles=intersectPermissions(currentUserRoles,keyAllowedRoles)}if(userRolesTable&&roleClaimsTable&&claimsTable){let userClaimRows=await db.select({action:claimsTable.action,scope:roleClaimsTable.scope}).from(userRolesTable).innerJoin(roleClaimsTable,eq70(roleClaimsTable.roleId,userRolesTable.roleId)).innerJoin(claimsTable,eq70(claimsTable.id,roleClaimsTable.claimId)).where(eq70(userRolesTable.userId,apiKeyUserId)),currentUserClaims=[...new Set(userClaimRows.map((r)=>r.action).filter((a)=>a!==void 0))];effectiveClaims=intersectPermissions(currentUserClaims,keyAllowedClaims);let effectiveClaimSet=new Set(effectiveClaims),apiScopedRows=userClaimRows.filter((r)=>typeof r.action==="string"&&effectiveClaimSet.has(r.action)).map((r)=>({action:r.action,scope:r.scope??null}));if(apiScopedRows.some((r)=>!!r.scope)){let{claimScopes,dropped}=resolveClaimScopes(apiScopedRows,apiKeyUserData,logger2);if(apiKeyClaimScopes=claimScopes,dropped.length>0){let droppedSet=new Set(dropped);effectiveClaims=effectiveClaims.filter((a)=>!droppedSet.has(a))}}}if(db.update(apiKeysTableRef).set({lastUsedAt:new Date,lastUsedIp:clientIp,usageCount:apiKeyRecord.usageCount+1}).where(eq70(apiKeysTableRef.id,apiKeyRecord.id)).catch(()=>{}),effectiveRoles=effectiveRoles.filter((r)=>r!==GODMIN_ROLE_NAME),request.headers.set("x-user-id",apiKeyUserId),request.headers.set("x-auth-type","api_key"),request.headers.set("x-api-key-id",apiKeyRecord.id),request.headers.set("x-api-key-owner-type",apiKeyRecord.ownerType||"personal"),effectiveRoles.length>0)request.headers.set("x-user-roles",encodeHeaderList(effectiveRoles));if(effectiveClaims.length>0)request.headers.set("x-user-claims",encodeHeaderList(effectiveClaims));{let apiEncodedScopes=encodeClaimScopesHeader(apiKeyClaimScopes);if(apiEncodedScopes)request.headers.set("x-user-claim-scopes",apiEncodedScopes)}logger2.info("[AUTH] API key authenticated",{userId:apiKeyUserId,keyId:apiKeyRecord.id,ownerType:apiKeyRecord.ownerType,path:pathname,method,effectiveRoles:effectiveRoles.length,effectiveClaims:effectiveClaims.length});return}if(!authentication.accessToken?.secret)return set2.status=500,logger2.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:pathname,method},audit:toAudit(auditPayload,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(authentication.mode==="consumer"){tokens=parseTokenValuesFromHeaders(request.headers,tokenNames);let jwtResult=verifyJWT(tokens.access_token||"",envResolved.accessTokenSecret||"",{issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience});if(!jwtResult.valid)return set2.status=401,logger2.traceSync({message:"Invalid or missing access token",level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,"Invalid or missing access token",{userId:decodeUnverifiedSubject(tokens.access_token)})}),Error("Unauthenticated");let consumerBinding=verifyTenantBinding(jwtResult.payload[TENANT_CLAIM],request.headers.get("x-tenant-schema"),resolvedOptions.authentication?.tenantBinding??"lenient");if(!consumerBinding.ok)return set2.status=401,logger2.traceSync({message:"Access token tenant binding failed",level:"warn",context:{path:pathname,method,reason:consumerBinding.reason},audit:toAudit(auditPayload,"Access token tenant binding failed",{userId:decodeUnverifiedSubject(tokens.access_token)})}),Error("Unauthenticated");let userId=jwtResult.payload.sub,roles=jwtResult.payload.roles,claimsFromToken=jwtResult.payload.claims;if(request.headers.set("x-access-token",tokens.access_token||""),request.headers.set("x-user-id",userId||""),roles&&roles.length>0)request.headers.set("x-user-roles",encodeHeaderList(roles));if(claimsFromToken&&claimsFromToken.length>0)request.headers.set("x-user-claims",encodeHeaderList(claimsFromToken));{let encodedScopes=encodeClaimScopesHeader(jwtResult.payload.claimScopes);if(encodedScopes)request.headers.set("x-user-claim-scopes",encodedScopes)}}else{if(!authentication.refreshToken?.secret||!authentication.sessionToken?.secret)return set2.status=500,logger2.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:pathname,method},audit:toAudit(auditPayload,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(tokens=parseTokenValuesFromHeaders(request.headers,tokenNames),!tokens.session_token)return set2.status=401,logger2.traceSync({message:"No session token",level:"debug",context:{path:pathname,method},audit:toAudit(auditPayload,"No session token")}),Error("Unauthenticated");let sessionData=await readSession({sessionId:tokens.session_token});if(!sessionData)return set2.status=401,logger2.traceSync({message:"Invalid session",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token},audit:toAudit(auditPayload,"Invalid session")}),Error("Unauthenticated");let sessionsTableCheck=requestSchemaTables.userSessions;if(sessionsTableCheck&&db){let session=(await db.select().from(sessionsTableCheck).where(eq70(sessionsTableCheck.id,tokens.session_token)).limit(1))[0],revokedAtVal=session?.revokedAt,isRevoked=revokedAtVal!=null&&!(typeof revokedAtVal==="object"&&!(revokedAtVal instanceof Date)&&Object.keys(revokedAtVal).length===0);if(!session||session.isActive===!1||isRevoked)return set2.status=401,logger2.traceSync({message:"Session revoked or inactive",level:"warn",context:{path:pathname,method,sessionId:tokens.session_token,isActive:session?.isActive,revokedAt:session?.revokedAt},audit:toAudit(auditPayload,"Session revoked",{userId:sessionData.userId??null})}),Error("Session has been revoked");if(session.expiresAt&&new Date(session.expiresAt)<new Date)return set2.status=401,logger2.traceSync({message:"Session expired",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token,expiresAt:session.expiresAt},audit:toAudit(auditPayload,"Session expired",{userId:sessionData.userId??null})}),Error("Session has expired")}let accountTable=requestSchemaTables.users;if(accountTable&&db&&sessionData.userId){let account=(await db.select().from(accountTable).where(eq70(accountTable.id,sessionData.userId)).limit(1))[0];if(account?.isActive===!1)return set2.status=401,logger2.traceSync({message:"Account deactivated",level:"warn",context:{path:pathname,method,userId:sessionData.userId},audit:toAudit(auditPayload,"Account deactivated",{userId:sessionData.userId??null})}),Error("Account is not active");if(!account)logger2.traceSync({message:"Session user row did not resolve; account state unchecked",level:"warn",context:{path:pathname,method,userId:sessionData.userId}})}if(isIdleExpired({lastActiveAt:sessionData.lastActiveAt,inactivityTimeout:authentication.sessions?.inactivityTimeout}))return set2.status=401,logger2.traceSync({message:"Session inactive timeout",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token,lastActiveAt:sessionData.lastActiveAt},audit:toAudit(auditPayload,"Session inactive timeout",{userId:sessionData.userId??null})}),Error("Session expired due to inactivity");updateLastActiveAt(tokens.session_token).catch(()=>{});let sessionsTableRef=requestSchemaTables.userSessions;if(sessionsTableRef&&db)db.update(sessionsTableRef).set({lastActivityAt:new Date}).where(eq70(sessionsTableRef.id,tokens.session_token)).catch(()=>{});let jwtResult=verifyJWT(tokens.access_token||"",envResolved.accessTokenSecret||"",{issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience}),isAccessTokenValid=tokens.access_token?jwtResult.valid:!1,isRefreshTokenValid=tokens.refresh_token?verifyJWT(tokens.refresh_token,envResolved.refreshTokenSecret||"",{issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience}).valid:!1;if(!isAccessTokenValid&&isRefreshTokenValid&&tokens.refresh_token&&sessionData.rememberMe===!0){let killSwitchUsersTable=requestSchemaTables.users;if(db&&killSwitchUsersTable){let ksUser=(await db.select().from(killSwitchUsersTable).where(eq70(killSwitchUsersTable.id,sessionData.userId)).limit(1))[0],{evaluateAccountState:evaluateAccountState2}=await Promise.resolve().then(() => exports_accountState),ksState=ksUser?evaluateAccountState2(ksUser):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!ksState.allowed)return set2.status=401,logger2.traceSync({message:`Silent refresh blocked - account ${ksState.reason}`,level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,`Silent refresh blocked - account ${ksState.reason}`,{userId:sessionData.userId??null})}),Error(ksState.message)}let refreshRoles=[],refreshClaims=[],refreshClaimScopes={},refreshUserRolesTable=requestSchemaTables.userRoles,refreshRolesTable=requestSchemaTables.roles,refreshRoleClaimsTable=requestSchemaTables.roleClaims,refreshClaimsTable=requestSchemaTables.claims;if(db&&refreshUserRolesTable&&refreshRolesTable)try{let{fetchUserRolesAndClaims:fetchUserRolesAndClaims2}=await Promise.resolve().then(() => (init_fetchUserRolesAndClaims(),exports_fetchUserRolesAndClaims)),rc=await fetchUserRolesAndClaims2(db,sessionData.userId,{usersTable:killSwitchUsersTable??null,sessionsTable:null,userRolesTable:refreshUserRolesTable,rolesTable:refreshRolesTable,roleClaimsTable:refreshRoleClaimsTable,claimsTable:refreshClaimsTable,oauthAccountsTable:void 0,apiKeysTable:void 0,schemaTables:requestSchemaTables});refreshRoles=rc.roles,refreshClaims=rc.claims,refreshClaimScopes=rc.claimScopes}catch{}let refreshResult=await refreshAccessTokenWithLock(sessionData.userId,sessionData.id,()=>signNewAccessToken({refreshTokenId:tokens.refresh_token,options:resolvedOptions,sessionData,roles:refreshRoles.length>0?refreshRoles:void 0,claims:refreshClaims.length>0?refreshClaims:void 0,claimScopes:refreshClaimScopes,tenant:request.headers.get("x-tenant-schema")??void 0,resolveMode:resolvedOptions.authorization?.jwtClaimsMode==="resolve"&&!!claimsCache}));if(refreshResult.success&&refreshResult.accessToken){tokens.access_token=refreshResult.accessToken;let rawDomain=authentication.cookieDomain,resolvedDomainRaw=rawDomain?process.env[rawDomain]??rawDomain:void 0,resolvedDomain=resolvedDomainRaw==="localhost"||resolvedDomainRaw===".localhost"?void 0:resolvedDomainRaw,domainPart=resolvedDomain?`; Domain=${resolvedDomain}`:"",bufferSeconds=authentication.cookieMaxAgeBufferSeconds??0,maxAge=Math.max(0,parseTimeToSeconds2(authentication.accessToken.expiresIn??"15m")-bufferSeconds),securePart=!resolvedDomain?"":"; Secure",cookieValue=`${tokenNames.access_token}=${refreshResult.accessToken}; Path=/; HttpOnly; SameSite=Lax${securePart}; Max-Age=${maxAge}${domainPart}`;set2.headers["Set-Cookie"]=cookieValue}}if(jwtResult.valid){let fullBinding=verifyTenantBinding(jwtResult.payload[TENANT_CLAIM],request.headers.get("x-tenant-schema"),resolvedOptions.authentication?.tenantBinding??"lenient");if(!fullBinding.ok)return set2.status=401,logger2.traceSync({message:"Access token tenant binding failed",level:"warn",context:{path:pathname,method,reason:fullBinding.reason},audit:toAudit(auditPayload,"Access token tenant binding failed",{userId:jwtResult.payload.sub??null})}),Error("Unauthenticated")}if(jwtResult.valid&&jwtResult.payload.sub&&String(jwtResult.payload.sub)!==String(sessionData.userId))return set2.status=401,logger2.traceSync({message:"Access token subject does not match session",level:"warn",context:{path:pathname,method,sessionUserId:sessionData.userId,tokenSub:jwtResult.payload.sub},audit:toAudit(auditPayload,"Access token/session subject mismatch",{userId:sessionData.userId??null})}),Error("Unauthenticated");let userId=jwtResult.valid?jwtResult.payload.sub:sessionData.userId,roles=jwtResult.valid?jwtResult.payload.roles:void 0,claimsFromToken=jwtResult.valid?jwtResult.payload.claims:void 0;if(!jwtResult.valid&&userId&&db){let{userRoles:sessionUserRolesTable,roles:sessionRolesTable}=requestSchemaTables;if(sessionUserRolesTable&&sessionRolesTable)try{let{fetchUserRolesAndClaims:fetchUserRolesAndClaims2}=await Promise.resolve().then(() => (init_fetchUserRolesAndClaims(),exports_fetchUserRolesAndClaims)),sessionRc=await fetchUserRolesAndClaims2(db,userId,{usersTable:requestSchemaTables.users??null,sessionsTable:null,userRolesTable:sessionUserRolesTable,rolesTable:sessionRolesTable,roleClaimsTable:requestSchemaTables.roleClaims,claimsTable:requestSchemaTables.claims,oauthAccountsTable:void 0,apiKeysTable:void 0,schemaTables:requestSchemaTables});if(sessionRc.roles.length>0)roles=sessionRc.roles;if(sessionRc.claims.length>0)claimsFromToken=sessionRc.claims}catch(err){logger2.traceSync({message:"Session-authenticated role resolution failed",level:"warn",context:{path:pathname,method,error:String(err)}})}}if(!claimsFromToken?.length&&claimsCache&&roles&&roles.length>0)try{let resolvedClaims=await claimsCache.resolveClaimsForRoles(roles);if(resolvedClaims.length>0)claimsFromToken=resolvedClaims}catch{}if(userId&&db&&authentication.cohorts?.enabled){let mwUsersTable=requestSchemaTables.users;if(mwUsersTable)try{let mwCohortId=(await db.select().from(mwUsersTable).where(eq70(mwUsersTable.id,userId)).limit(1))[0]?.cohortId;if(mwCohortId){let mwCohortsTable=requestSchemaTables.userCohorts??requestSchemaTables.user_cohorts;if(mwCohortsTable){let mwExpiresAt=(await db.select().from(mwCohortsTable).where(eq70(mwCohortsTable.id,mwCohortId)).limit(1))[0]?.expiresAt;if(mwExpiresAt&&new Date(mwExpiresAt)<new Date)return set2.status=403,logger2.traceSync({message:"Cohort expired - access denied",level:"warn",context:{path:pathname,method,userId,cohortId:mwCohortId},audit:toAudit(auditPayload,"Cohort expired",{userId:userId??null})}),Error("Your access has expired. Please contact your administrator.")}}}catch{}}if(request.headers.set("x-access-token",tokens.access_token||""),request.headers.set("x-refresh-token",tokens.refresh_token||""),request.headers.set("x-session-id",tokens.session_token||""),request.headers.set("x-user-id",userId||""),roles&&roles.length>0)request.headers.set("x-user-roles",encodeHeaderList(roles));if(claimsFromToken&&claimsFromToken.length>0)request.headers.set("x-user-claims",encodeHeaderList(claimsFromToken));{let encodedScopes=encodeClaimScopesHeader(jwtResult.valid?jwtResult.payload.claimScopes:void 0);if(encodedScopes)request.headers.set("x-user-claim-scopes",encodedScopes)}}}if(rateLimiter&&!isPublic&&rateLimiterUserBudgetPending){let resolvedUserId=request.headers.get("x-user-id");if(resolvedUserId){let perUser=await rateLimiter.check({ip:clientIp,userId:resolvedUserId,endpoint:pathname,category:"private"});if(perUser.remaining>=0)for(let[key2,value2]of Object.entries(rateLimiter.getHeaders(perUser)))set2.headers[key2]=value2;if(!perUser.allowed)return refuseRateLimited("user",perUser.retryAfter,`user ${resolvedUserId}`)}}},afterHandler=({request,set:set2})=>{let afterUrl=new URL(request.url),afterStatus=typeof set2.status==="number"?set2.status:200,afterStartStr=request.headers.get("x-request-start-time"),afterDuration=afterStartStr?Date.now()-parseInt(afterStartStr,10):0;if(requestLogConfig.enabled&&!isRequestLogExcluded(afterUrl.pathname)){let isSlow=afterDuration>=requestLogConfig.slowThresholdMs,level=afterStatus>=500?"error":afterStatus>=400||isSlow?"warn":"info";logger2.log(level,`\u2190 ${request.method} ${afterUrl.pathname} ${afterStatus} (${afterDuration}ms)`,{requestId:request.headers.get("x-request-id")||void 0,method:request.method,path:afterUrl.pathname,query:requestLogConfig.includeQuery&&afterUrl.search?afterUrl.search:void 0,statusCode:afterStatus,durationMs:afterDuration,slow:isSlow||void 0,userId:request.headers.get("x-user-id")||void 0,authType:request.headers.get("x-auth-type")||void 0,tenant:request.headers.get("x-tenant-schema")||void 0,ip:request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||request.headers.get("x-real-ip")||void 0},void 0,void 0,"middleware.request")}if(monitoringService){let startTimeStr=request.headers.get("x-request-start-time"),startTime=startTimeStr?parseInt(startTimeStr,10):Date.now(),responseTimeMs=Date.now()-startTime,url=new URL(request.url),status=typeof set2.status==="number"?set2.status:200;monitoringService.recordRequest({endpoint:url.pathname,method:request.method,status,responseTimeMs,isError:status>=500,errorType:status>=500?"server_error":status>=400?"client_error":void 0})}if(liveMonitoringService){let url=new URL(request.url),headersObj=redactSensitiveHeaders(request.headers);liveMonitoringService.recordRequest({path:url.pathname,method:request.method,timestamp:Date.now(),headers:headersObj})}};recordAdapterStep((app)=>{app.onRequest(authMiddleware).onAfterHandle(afterHandler)});let errorResponder=(ctx)=>{let{set:set2,code,error:error3,request}=ctx,status=statusOfError(code,error3),message="Internal Server Error",pgCode,clientSafe=!1;if(error3 instanceof Error){let cause=error3.cause;if(pgCode=cause?.code,pgCode==="23505")message="A record with this value already exists",clientSafe=!0,status=409;else if(pgCode==="23503"){let detail=String(cause?.detail??"");if(detail.includes("is still referenced from")){let referencing=detail.match(/is still referenced from table "([^"]+)"/)?.[1];message=referencing?`Cannot delete: records in '${referencing}' still reference this one. Remove them first.`:"Cannot delete: another record still references this one",status=409}else message="Referenced record does not exist",status=400;clientSafe=!0}else if(pgCode==="23502")message=`Missing required field: ${cause?.column||"a required field is empty"}`,clientSafe=!0,status=400;else if(pgCode==="23514")message=String(cause?.message??"A database constraint refused this value"),clientSafe=!0,status=400;else if(pgCode==="22003")message="A value is out of range for its field",clientSafe=!0,status=400;else if(pgCode==="22P02")message=cause?.routine==="string_to_uuid"?"Invalid ID format":"Invalid data format",clientSafe=!0,status=400;else if(pgCode)message=`Database error (${pgCode}): ${cause?.detail||cause?.message||error3.message}`;else if(code==="VALIDATION")message=describeValidationError(error3)??error3.message,clientSafe=!0;else message=error3.message,clientSafe=status<500}try{let errUrl=new URL(request.url),errStartStr=request.headers.get("x-request-start-time");logger2.log(status>=500?"error":"warn",`\u2716 ${request.method} ${errUrl.pathname} ${status}: ${message}`,{requestId:request.headers.get("x-request-id")||void 0,method:request.method,path:errUrl.pathname,statusCode:status,elysiaCode:typeof code==="string"?code:void 0,pgCode,durationMs:errStartStr?Date.now()-parseInt(errStartStr,10):void 0,userId:request.headers.get("x-user-id")||void 0,tenant:request.headers.get("x-tenant-schema")||void 0},status>=500?error3:void 0)}catch(logErr){logger2.error("Failed to log request error",logErr)}set2.status=status;let clientMessage=clientSafe?message:"Internal Server Error",requestId=request.headers.get("x-request-id")||void 0;if(requestId)set2.headers["x-request-id"]=requestId;return Response.json(withEnvelopeFlags({isSuccess:!1,message:clientMessage,status,requestId,errors:[{message:clientMessage}],data:null}))};recordAdapterStep((app)=>{app.onError(errorResponder)});let featureAdminRoles={};for(let[feature,section]of Object.entries(resolvedOptions)){if(!section||typeof section!=="object")continue;let roles=section.adminRoles;if(!Array.isArray(roles))continue;let named=roles.filter((role)=>typeof role==="string"&&role.length>0);if(named.length>0)featureAdminRoles[feature]=named}let onEntityWritten=resolvedOptions.verification?.enabled&&db?(info)=>{let ctx=tenantRegistry?.getSchemaContext(info.request.headers.get("x-tenant-schema")??""),{buildVerificationServices:buildVerificationServices2}=(init_buildServices(),__toCommonJS(exports_buildServices)),{verificationService:svc}=buildVerificationServices2({db,schemaTables:ctx?.schemaTables??schemaTables,config:resolvedOptions.verification,notificationConfig:resolvedOptions.notification,logger:logger2,getEmailService});svc.startIfTriggered({entity_name:info.entityName,entity_id:info.entityId,operation:info.operation,started_by:info.userId}).catch((err)=>{logger2.error(`[Verification] trigger after ${info.operation} of ${info.entityName}:${info.entityId} failed: ${String(err)}`)})}:void 0;logger2.info("Creating routes for entities"),createEntityRoutes(plugin,{onEntityWritten,db,schemaTables,schemaRelations,entities,logger:logger2,databaseUrl:envResolved.databaseUrl,dbPool,storage:resolvedOptions.storage,cdnMedia:{transform:mergeTransformConfig(resolvedOptions.storage?.cdn?.transform),video:mergeVideoConfig(resolvedOptions.storage?.cdn?.video),pdf:mergePdfConfig(resolvedOptions.storage?.cdn?.pdf)},authorization:resolvedOptions.authorization,featureAdminRoles,accountLinks:authentication?.accountLinks,authMode:authentication?.mode,idpUrl:authentication?.idpUrl?process.env[authentication.idpUrl]||authentication.idpUrl:void 0,isEmailServiceAvailable:()=>!!getEmailService()?.isAvailable(),onRoleChanged:({userId:subjectId,roleName,assigned})=>{if(!db)return;let service=new NotificationService({db,schemaTables,config:resolvedOptions.notification??{},logger:logger2,getEmailService}),title=assigned?`New role: ${roleName}`:`Role removed: ${roleName}`,body=assigned?`You have been given the "${roleName}" role in the portal. New sections will appear in your menu.`:`Your "${roleName}" role in the portal has been removed. The sections it opened will no longer appear.`;service.send({user_id:subjectId,title,body,type:"system",source:"authorization",channels:["portal","email"]}).catch(()=>{})},tenantRegistry,getTenantRegistry:()=>tenantRegistry,claimsCache});let isConsumerMode=authentication?.mode==="consumer";if(isMultiTenant&&!isConsumerMode)createTenantRoutes(plugin,{getDb:()=>db,logger:logger2,getTenantRegistry:()=>tenantRegistry,schemaName:targetSchemaName}),logger2.info("[MultiTenant] Tenant routes pre-registered (handlers check runtime readiness)");else if(isMultiTenant&&isConsumerMode){let routePostTenantsRefresh=defineRoute({method:"POST",path:"/tenants/refresh",handler:async(ctx)=>{if(!tenantRegistry||!tenantRegistry.isConsumerMode())return ctx.set.status=503,{success:!1,message:"Tenant registry not ready"};try{return{success:!0,data:await tenantRegistry.syncFromIdp()}}catch(err){let msg=err instanceof Error?err.message:String(err);return ctx.set.status=500,{success:!1,message:`Tenant sync failed: ${msg}`}}}});mountRoutes(plugin,[{routes:[routePostTenantsRefresh]}]),logger2.info("[MultiTenant] Consumer tenant refresh route registered (/tenants/refresh)")}let domainServices=null;if(resolvedOptions.domains?.enabled){if(domainServices=createDomainServices({options:resolvedOptions,logger:logger2,getDb:()=>db,getTenantRegistry:()=>tenantRegistry}),domainServices)createDomainRoutes(plugin,{getDomainService:()=>domainServices?.domainService??null,getRegistrationService:()=>domainServices?.registrationService??null,logger:logger2,basePath:resolvedOptions.domains.basePath||"/domains",resolveTenantIdForSchema:(schema3)=>schema3&&tenantRegistry?tenantRegistry.getTenantBySchemaName(schema3)?.id??null:null}),logger2.info("[Domains] Custom domain routes registered",{provider:domainServices.domainService.config.provider,basePath:resolvedOptions.domains.basePath||"/domains"})}if(authentication?.enabled&&!isConsumerMode&&db){let resolveTableForTenant=(tableName,reqSchemaName)=>{if(reqSchemaName&&tenantRegistry){let ctx=tenantRegistry.getSchemaContext(reqSchemaName);if(ctx?.schemaTables[tableName])return ctx.schemaTables[tableName]}return schemaTables[tableName]},usersTable=schemaTables.users,sessionsTable=schemaTables.userSessions||schemaTables.user_sessions||schemaTables.sessions;if(!sessionsTable&&authentication.sessions?.enabled)logger2.warn("[AUTH] sessions is enabled but user_sessions table not found in schema. Disabling sessions.");if(usersTable){await initiateRedisManager(resolvedOptions);let{createAuthRoutes:createAuthRoutes2}=(init_auth(),__toCommonJS(exports_auth)),{signJWT:signJWT2,verifyJWT:verifyJWT3}=(init_JWT(),__toCommonJS(exports_JWT)),{generateSession:generateSession2,deleteSession:deleteSession2}=(init_SessionStore(),__toCommonJS(exports_SessionStore));createAuthRoutes2(plugin,{authConfig:{db,logger:logger2,usersTable,sessionsTable,userRolesTable:schemaTables.userRoles,rolesTable:schemaTables.roles,roleClaimsTable:schemaTables.roleClaims,claimsTable:schemaTables.claims,authentication:{enabled:authentication.enabled,mode:authentication.mode,get defaultRole(){return resolvedOptions.authentication?.defaultRole||process.env.AUTH_DEFAULT_ROLE},get defaultRoles(){return resolvedOptions.authentication?.defaultRoles},cookieDomain:resolvedOptions.authentication?.cookieDomain,get trustedAppOrigins(){return trustedAppOrigins()},emailExemptDomains:authentication?.emailExemptDomains,passwordPolicy:authentication?.passwordPolicy,emailVerificationTemplates:authentication?.register?.emailVerification?.templates,accessToken:authentication.accessToken,refreshToken:authentication.refreshToken,sessionToken:authentication.sessionToken,rememberMe:authentication.rememberMe,deviceTrust:authentication.sessions?.deviceTrust}},features:{login:authentication.login,register:authentication.register,logout:authentication.logout,refresh:authentication.refresh,passwordReset:withResolvedRedirects(authentication.passwordReset,["redirectUrl"]),passwordChange:authentication.passwordChange,passwordSet:authentication.passwordSet,sessions:withResolvedRedirects(authentication.sessions,["approvalRedirectUrl"]),magicLink:withResolvedRedirects(authentication.magicLink,["redirectUrl"]),me:authentication.me||{enabled:!0,route:"/auth/me"},invite:withResolvedRedirects(authentication.invite,["redirectUrl"]),captcha:authentication.captcha,oauth:authentication.oauth?.enabled&&envResolved.oauthProviders?{...withResolvedRedirects(authentication.oauth,["successRedirectUrl","errorRedirectUrl"]),providers:liveOAuthProviders(envResolved.oauthProviders)}:void 0,apiKeys:authentication.apiKeys?.enabled?{enabled:!0,route:authentication.apiKeys.route,keyPrefix:authentication.apiKeys.keyPrefix,maxKeysPerUser:authentication.apiKeys.maxKeysPerUser,defaultExpiresIn:authentication.apiKeys.defaultExpiresIn,allowApplicationKeys:authentication.apiKeys.allowApplicationKeys,preventApiKeyManagement:authentication.apiKeys.preventApiKeyManagement}:void 0,webauthn:authentication.webauthn},sessionsTable,oauthAccountsTable:schemaTables.oauthAccounts,oauthStateStore:(()=>{let oauthRedis=getRedisManager();if(!oauthRedis)return;let{createRedisOAuthStateStore:createRedisOAuthStateStore2}=__toCommonJS(exports_stateStore);return createRedisOAuthStateStore2(oauthRedis)})(),apiKeysTable:schemaTables.apiKeys,schemaTables,schemaRelations,tenantRegistry,getTenantRegistry:()=>tenantRegistry,databaseUrl:envResolved.databaseUrl,dbPool,admin:(()=>{let adminCfg=resolvedOptions.authentication?.admin;return{impersonate:{enabled:!0},changeUserId:{enabled:!0},createUser:adminCfg?.createUser??{enabled:!0},passwordTools:adminCfg?.passwordTools??{enabled:!1}}})(),schemaName:targetSchemaName,getEmailService,appName:resolvedOptions.appId,webauthnService:(()=>{if(!authentication.webauthn?.enabled||!db)return null;let{WebAuthnService:WebAuthnService2}=(init_WebAuthn(),__toCommonJS(exports_WebAuthn)),{createDbWebAuthnStorage:createDbWebAuthnStorage2}=(init_dbStorage(),__toCommonJS(exports_dbStorage)),rpName=authentication.webauthn.rpName||resolvedOptions.appId||"Nucleus",rpID=authentication.webauthn.rpID||"localhost",expectedOrigins=authentication.webauthn.expectedOrigins||[`http://${rpID}`,`https://${rpID}`],challengeTtlMs=authentication.webauthn.challengeTtl?parseTimeToSeconds2(authentication.webauthn.challengeTtl)*1000:300000,storage=createDbWebAuthnStorage2({db,resolveTable:resolveTableForTenant});return new WebAuthnService2({rp:{rpName,rpID,expectedOrigins},challengeTtlMs,storage,userVerification:authentication.webauthn?.userVerification,logger:logger2})})(),captchaService:(()=>{let redisManager=getRedisManager();if(!authentication.captcha?.enabled||!redisManager)return null;return new CaptchaService({redis:{get:async(key2)=>{let result=await redisManager.read(key2);return result.success?result.data:null},set:async(key2,value2,options)=>{await redisManager.create(key2,value2,options?.ex)},del:async(key2)=>{await redisManager.remove(key2)},incrementCounter:(key2,delta,ttlSeconds)=>redisManager.incrementCounter(key2,delta,ttlSeconds)},logger:logger2,config:{enabled:!0,type:authentication.captcha.type||"math",difficulty:authentication.captcha.difficulty||"medium",expiresIn:authentication.captcha.expiresIn||"5m",maxAttempts:authentication.captcha.maxAttempts||3,caseSensitive:authentication.captcha.caseSensitive??!1}})})(),tokenResponseConfig:{accessToken:{setHeadersEnabled:authentication.accessToken?.setHeadersEnabled??!0,returnJson:authentication.accessToken?.returnJson??!0},refreshToken:{setHeadersEnabled:authentication.refreshToken?.setHeadersEnabled??!0,returnJson:authentication.refreshToken?.returnJson??!0},sessionToken:{setHeadersEnabled:authentication.sessionToken?.setHeadersEnabled??!0,returnJson:authentication.sessionToken?.returnJson??!0}},helpers:{signAccessToken:(userId,roles,claims,tenant,claimScopes,sessionId)=>{let resolveMode=resolvedOptions.authorization?.jwtClaimsMode==="resolve"&&claimsCache,hasClaimScopes=!resolveMode&&!!claimScopes&&Object.keys(claimScopes).length>0,token=signJWT2({subject:userId,expiresInSeconds:parseTimeToSeconds2(authentication.accessToken?.expiresIn||"15m"),issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience,sessionId,customClaims:{...roles&&roles.length>0?{roles}:{},...!resolveMode&&claims&&claims.length>0?{claims}:{},...hasClaimScopes?{claimScopes}:{},...tenant?{tenant}:{}}},envResolved.accessTokenSecret||"",authentication.accessToken?.algorithm||"HS256");return warnIfAccessTokenTooLargeForCookie(token,resolveMode?"resolve":resolvedOptions.authorization?.jwtClaimsMode),token},signRefreshToken:(userId,rememberMe,sessionId)=>signJWT2({subject:userId,expiresInSeconds:longerLifetime(rememberMe?authentication.rememberMe?.expiresIn:void 0,authentication.refreshToken?.expiresIn,604800),issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience,sessionId},envResolved.refreshTokenSecret||"",authentication.refreshToken?.algorithm||"HS256"),verifyRefreshToken:(token)=>verifyJWT3(token,envResolved.refreshTokenSecret||"",{issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience}),createSession:async(params)=>{let sessionTtlSeconds=longerLifetime(params.rememberMe?authentication.rememberMe?.expiresIn:void 0,authentication.sessionToken?.expiresIn,2592000),result=await generateSession2({userId:params.userId,deviceInfo:params.deviceInfo,rememberMe:params.rememberMe,loginMethod:params.loginMethod,expiresInSeconds:sessionTtlSeconds});if(!result.success)throw logger2.error("[createSession] failed to create session",{userId:params.userId,error:result.error}),Error(`Session storage unavailable: ${result.error||"unknown error"}`);return result.session.id},destroySession:async(sessionId)=>deleteSession2({sessionId}),saveSessionToDb:async(sessionId,params,reqSchemaName)=>{let resolvedSessionsTable=resolveTableForTenant("userSessions",reqSchemaName)||resolveTableForTenant("user_sessions",reqSchemaName)||resolveTableForTenant("sessions",reqSchemaName)||sessionsTable;if(!resolvedSessionsTable||!db)return;let sessionsConfig=authentication.sessions,deviceInfo=ensureDeviceInfo(params.deviceInfo||{ipAddress:""}),resolvedUsersTableForExempt=resolveTableForTenant("users",reqSchemaName),sessionUserEmail=null;if(resolvedUsersTableForExempt)sessionUserEmail=(await db.select().from(resolvedUsersTableForExempt).where(eq70(resolvedUsersTableForExempt.id,params.userId)).limit(1))[0]?.email??null;let userIsEmailExempt=sessionUserEmail?isEmailExempt(sessionUserEmail,authentication?.emailExemptDomains):!1,deviceFingerprint=deviceInfo.deviceHint?`${deviceInfo.browserName||""}-${deviceInfo.osName||""}-${deviceInfo.deviceType||""}-${deviceInfo.deviceHint}`:`${deviceInfo.browserName||""}-${deviceInfo.osName||""}-${deviceInfo.deviceType||""}`,existingSessions=await db.select().from(resolvedSessionsTable).where(and30(eq70(resolvedSessionsTable.userId,params.userId),eq70(resolvedSessionsTable.isActive,!0))),hasValidFingerprint=deviceFingerprint&&!deviceFingerprint.includes("--unknown")&&!deviceFingerprint.includes("Bot/Crawler")&&!deviceFingerprint.includes("Headless")&&deviceFingerprint!=="--"&&deviceFingerprint!=="--unknown",allUserSessions=await db.select().from(resolvedSessionsTable).where(eq70(resolvedSessionsTable.userId,params.userId)),isNewDevice=hasValidFingerprint?!existingSessions.some((s)=>s.deviceFingerprint===deviceFingerprint):!1,wasPreviouslyApproved=hasValidFingerprint?allUserSessions.some((s)=>{let sess=s;return sess.deviceFingerprint===deviceFingerprint&&sess.approvalStatus==="approved"}):!1,hasAnyApprovedSession=existingSessions.some((s)=>s.approvalStatus==="approved"),isImpersonationLogin=params.loginMethod==="impersonation"||params.loginMethod==="impersonation_stop",isOAuthLogin=params.loginMethod?.startsWith("oauth:"),requiresApproval=!isImpersonationLogin&&!userIsEmailExempt&&sessionsConfig?.trustNewDevices===!1&&isNewDevice&&!wasPreviouslyApproved&&hasValidFingerprint&&hasAnyApprovedSession,deviceTrustCfg=sessionsConfig?.deviceTrust,dtTable=deviceTrustCfg?.enabled?resolveTableForTenant("trustedDevices",reqSchemaName)||resolveTableForTenant("trusted_devices",reqSchemaName):void 0,deviceTrustMint=null,deviceTokenToSet=null;if(deviceTrustCfg?.enabled&&dtTable){let DT=await Promise.resolve().then(() => (init_DeviceTrust(),exports_DeviceTrust)),DTStore=await Promise.resolve().then(() => (init_store3(),exports_store)),dtNow=new Date,dtRows=params.deviceToken?await DTStore.findDeviceRowsByRawToken(db,dtTable,params.deviceToken):[],knownRow=DT.selectUsableDeviceRow(dtRows,params.userId,dtNow),pendingRow=dtRows.find((r)=>(r.userId??r.user_id)===params.userId&&r.status==="pending"),isFirstEver=allUserSessions.length===0&&await DTStore.userHasNoTrustedDevices(db,dtTable,params.userId),decision=DT.decideDeviceApproval({knownDevice:!!knownRow,trustNewDevices:sessionsConfig?.trustNewDevices??!0,hasValidFingerprint:!!hasValidFingerprint,isFirstEverDevice:isFirstEver,loginMethod:params.loginMethod,approvalMethods:deviceTrustCfg.approvalMethods??["password","magic_link","sso","webauthn","oauth:*","register"],onUnidentifiable:deviceTrustCfg.onUnidentifiable??"require_approval",isImpersonation:isImpersonationLogin,isEmailExempt:userIsEmailExempt});if(knownRow)await DTStore.touchDevice(db,dtTable,knownRow.id,deviceInfo.ipAddress).catch(()=>{});if(decision.deny)return logger2.warn("[AUTH] Device-trust denied unidentifiable device",{userId:params.userId}),{requiresApproval:!1,denied:!0};let reuseSessionId=pendingRow?.originSessionId??pendingRow?.origin_session_id;if(decision.requiresApproval&&reuseSessionId)return{requiresApproval:!0,sessionId:reuseSessionId};requiresApproval=decision.requiresApproval,deviceTrustMint=decision.mintToken?decision.trustImmediately?"trusted":"pending":null}logger2.info("[AUTH] Device fingerprint analysis",{userId:params.userId,deviceFingerprint,hasValidFingerprint,isNewDevice,wasPreviouslyApproved,loginMethod:params.loginMethod,isImpersonationLogin,isOAuthLogin,existingSessionCount:existingSessions.length,hasAnyApprovedSession,requiresApproval});let approvalToken=null,approvalStatus="approved";if(requiresApproval){let existingPending=deviceTrustCfg?.enabled?void 0:allUserSessions.find((s)=>{let sess=s;return sess.deviceFingerprint===deviceFingerprint&&(sess.approvalStatus==="pending"||sess.approval_status==="pending")&&sess.approvalToken});if(existingPending){let pendingSess=existingPending,pendingRequestedAt=pendingSess.approvalRequestedAt||pendingSess.approval_requested_at;if(pendingRequestedAt?Date.now()-new Date(pendingRequestedAt).getTime()<86400000:!0)return logger2.info("[AUTH] Reusing existing pending session for same device",{userId:params.userId,deviceFingerprint,existingSessionId:pendingSess.id}),{requiresApproval:!0,sessionId:pendingSess.id}}let{randomBytes:randomBytes8}=await import("crypto");approvalToken=randomBytes8(32).toString("hex"),approvalStatus="pending",logger2.info("[AUTH] New device requires approval",{userId:params.userId,deviceFingerprint,ipAddress:deviceInfo.ipAddress})}let staleBotSessions=existingSessions.filter((s)=>{let sess=s,fp=(sess.deviceFingerprint||"").toLowerCase(),ip=sess.ipAddress||"",ua=(sess.userAgent||"").toLowerCase(),isBotFingerprint=!fp||fp==="--"||fp==="--unknown"||fp.includes("bot/crawler")||fp.includes("headless")||fp.includes("unknown-unknown"),isServerAction=ua.includes("nucleusserveraction")||ua.includes("serveraction")||ua.includes("node-fetch")||ua.includes("undici");return isBotFingerprint&&(ip==="127.0.0.1"||ip==="::1"||ip==="localhost"||!ip)||isServerAction});if(staleBotSessions.length>0){for(let botSession of staleBotSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"bot_session_cleanup"}).where(eq70(resolvedSessionsTable.id,botSession.id));logger2.info("[AUTH] Cleaned up stale bot/crawler sessions",{userId:params.userId,cleanedCount:staleBotSessions.length})}if(hasValidFingerprint&&!requiresApproval){let sameDeviceOldSessions=existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint);for(let oldSession of sameDeviceOldSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"same_device_relogin"}).where(eq70(resolvedSessionsTable.id,oldSession.id));if(sameDeviceOldSessions.length>0)logger2.info("[AUTH] Revoked old same-device sessions",{userId:params.userId,deviceFingerprint,revokedCount:sameDeviceOldSessions.length})}if(!sessionsConfig?.allowMultipleDevices&&existingSessions.length>0){if((hasValidFingerprint?existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint):[]).length===0)for(let oldSession of existingSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"new_device_login"}).where(eq70(resolvedSessionsTable.id,oldSession.id))}if(sessionsConfig?.maxActiveSessions){let{count:count3}=await import("drizzle-orm"),currentCount=(await db.select({count:count3()}).from(resolvedSessionsTable).where(and30(eq70(resolvedSessionsTable.userId,params.userId),eq70(resolvedSessionsTable.isActive,!0))))[0]?.count||0;if(currentCount>=sessionsConfig.maxActiveSessions){let{asc:asc3}=await import("drizzle-orm"),oldestSessions=await db.select().from(resolvedSessionsTable).where(and30(eq70(resolvedSessionsTable.userId,params.userId),eq70(resolvedSessionsTable.isActive,!0))).orderBy(sql15`${resolvedSessionsTable.lastActivityAt} ASC NULLS FIRST`,asc3(resolvedSessionsTable.createdAt)).limit(currentCount-sessionsConfig.maxActiveSessions+1);for(let oldSession of oldestSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"max_sessions_exceeded"}).where(eq70(resolvedSessionsTable.id,oldSession.id))}}let trustScore=100;if(deviceInfo.isHeadless)trustScore-=50;if(deviceInfo.isBot)trustScore-=40;if(deviceInfo.isSuspicious)logger2.warn("[AUTH] Suspicious login detected",{userId:params.userId,suspiciousPatterns:deviceInfo.suspiciousPatterns,userAgent:deviceInfo.userAgent,ipAddress:deviceInfo.ipAddress});if(isNewDevice)trustScore-=25;if(!deviceInfo.ipAddress||deviceInfo.ipAddress==="unknown")trustScore-=20;if(!deviceInfo.browserName)trustScore-=15;if(!deviceInfo.osName)trustScore-=15;if(!deviceInfo.deviceType||deviceInfo.deviceType==="unknown")trustScore-=10;if(!deviceInfo.deviceName||deviceInfo.deviceName==="Unknown Device")trustScore-=5;let validFingerprint=deviceFingerprint&&!deviceFingerprint.includes("--unknown")&&deviceFingerprint!=="--",validIp=deviceInfo.ipAddress&&deviceInfo.ipAddress!=="unknown";if(validFingerprint){if(existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint).length>0)trustScore+=20}if(validIp){if(existingSessions.filter((s)=>s.ipAddress===deviceInfo.ipAddress).length>0)trustScore+=15}trustScore=Math.max(0,Math.min(100,trustScore));let LOW_TRUST_THRESHOLD=50;if(await db.insert(resolvedSessionsTable).values({id:sessionId,userId:params.userId,tokenHash:sessionId,deviceFingerprint,deviceName:deviceInfo.deviceName,deviceType:deviceInfo.deviceType,browserName:deviceInfo.browserName,browserVersion:deviceInfo.browserVersion,osName:deviceInfo.osName,osVersion:deviceInfo.osVersion,ipAddress:deviceInfo.ipAddress,locationCountry:deviceInfo.locationCountry,locationCity:deviceInfo.locationCity,loginMethod:params.loginMethod||"password",rememberMe:params.rememberMe??!1,trustScore,lastActivityAt:new Date,createdAt:new Date,expiresAt:(()=>{let ttl=lifetimeSeconds(authentication.sessionToken?.expiresIn,2592000);return ttl===null?null:new Date(Date.now()+ttl*1000)})(),isActive:approvalStatus==="approved",approvalStatus,approvalToken,approvalRequestedAt:requiresApproval?new Date:null}),shouldNotifyDevice({emailAvailable:Boolean(getEmailService()?.isAvailable()),isImpersonationLogin:Boolean(isImpersonationLogin),notifyOnNewDevice:Boolean(sessionsConfig?.notifyOnNewDevice),isNewDevice,trustScore,lowTrustThreshold:LOW_TRUST_THRESHOLD,requiresApproval:Boolean(requiresApproval)})){let resolvedUsersTable=resolveTableForTenant("users",reqSchemaName);if(resolvedUsersTable){let user=(await db.select().from(resolvedUsersTable).where(eq70(resolvedUsersTable.id,params.userId)).limit(1))[0];if(user?.email&&!isEmailExempt(user.email,authentication?.emailExemptDomains)){let isLowTrust=trustScore<LOW_TRUST_THRESHOLD,sessionsRoute=authentication.sessions?.route||"/auth/sessions",configuredUrl=authentication.sessions?.approvalRedirectUrl||"",isLegacyFrontendUrl=!configuredUrl||configuredUrl.endsWith("/devices"),approvalBase;if(!isLegacyFrontendUrl)approvalBase=configuredUrl;else{let origin=pickTrustedOrigin(params.requestOrigin,configuredUrl,trustedAppOrigins());if(params.requestOrigin&&origin!==params.requestOrigin)logger2.warn("[AUTH] Device-approval link origin refused \u2014 not in trustedAppOrigins",{requested:params.requestOrigin,used:origin||"(none)"});approvalBase=`${origin||"http://localhost:9000"}${sessionsRoute}`}let approveUrl=approvalToken?`${approvalBase}/approve-page?token=${approvalToken}`:"",rejectUrl=approvalToken?`${approvalBase}/reject-page?token=${approvalToken}`:"",subject,emailHtml,brandName=resolvedOptions.appId||"Nucleus",loginTime=new Date().toLocaleString("en-US",{dateStyle:"medium",timeStyle:"short"}),deviceSummary=`${deviceInfo.browserName||"Unknown"} ${deviceInfo.browserVersion||""} on ${deviceInfo.osName||"Unknown"} ${deviceInfo.osVersion||""}`,emailWrapper=(content)=>`
|
|
554
|
+
`)}`);logger2.info(`[AUTH] Built ${publicRoutes.length} public routes`);let rateLimiter=null,warnedSharedRateLimitBucket=!1,peerDiversity=createPeerDiversityWatcher(),monitoringService=null,liveMonitoringService=null,lifecycleRecorder=null,LIFECYCLE_BEAT_MS=1e4,activeEmailProvider=()=>{let declared=resolveCredential("email","provider",resolvedOptions.email?.provider);if(declared==="azure"||declared==="gmail"||declared==="smtp")return emailProviderOn(declared)||resolvedOptions.email?.provider===declared?declared:null;if(emailProviderOn("azure"))return"azure";if(emailProviderOn("gmail"))return"gmail";if(emailProviderOn("smtp"))return"smtp";return null},emailProviderOn=(provider)=>{let configured=resolvedOptions.email?.[provider]?.enabled===!0;return secretsService?secretsService.flag(`email.${provider}`,"enabled",configured):configured},azureEmailCredentials=()=>{let azureConfig=resolvedOptions.email?.azure;return{enabled:!0,connectionString:resolveCredential("email.azure","connection_string",azureConfig?.connection_string)??"",senderAddress:resolveCredential("email.azure","sender_address",azureConfig?.sender_address)??"",fromName:resolveCredential("email.azure","from_name",azureConfig?.from_name)}},gmailCredentials=()=>{let gmailConfig=resolvedOptions.email?.gmail;return{enabled:!0,jsonFilePath:gmailConfig?.json_file_path,serviceAccountJson:resolveCredential("email.gmail","service_account_json",gmailConfig?.service_account_json),fromEmail:resolveCredential("email.gmail","from_email",gmailConfig?.from_email)??"",fromName:resolveCredential("email.gmail","from_name",gmailConfig?.from_name)}},smtpCredentials=()=>{let smtpConfig=resolvedOptions.email?.smtp,port=resolveCredential("email.smtp","port",smtpConfig?.port===void 0?void 0:String(smtpConfig.port)),secure=resolveCredential("email.smtp","secure",smtpConfig?.secure===void 0?void 0:String(smtpConfig.secure));return{enabled:!0,host:resolveCredential("email.smtp","host",smtpConfig?.host)??"",port:port?Number(port):void 0,secure:secure===void 0?void 0:String(secure)==="true",user:resolveCredential("email.smtp","user",smtpConfig?.user)??"",password:resolveCredential("email.smtp","password",smtpConfig?.password)??"",senderAddress:resolveCredential("email.smtp","sender_address",smtpConfig?.sender_address)??"",fromName:resolveCredential("email.smtp","from_name",smtpConfig?.from_name)}},azureService=null,gmailService=null,smtpService=null,getEmailService=()=>{let provider=activeEmailProvider();if(!provider)return null;if(provider==="azure"){if(!azureService)azureService=new AzureEmailService(azureEmailCredentials(),logger2),logger2.info("[AzureEmailService] Initialized",{available:azureService.isAvailable()});else azureService.reconfigure(azureEmailCredentials());return azureService}if(provider==="smtp"){if(!smtpService)smtpService=new SmtpEmailService(smtpCredentials(),logger2),logger2.info("[SmtpEmailService] Initialized",{available:smtpService.isAvailable()});else smtpService.applyConfig(smtpCredentials());return smtpService}if(!gmailService)gmailService=new GmailService(gmailCredentials(),logger2),logger2.info("[GmailService] Initialized",{available:gmailService.isAvailable()});else gmailService.reconfigure(gmailCredentials());return gmailService},nucleusRuntime=createNucleusRuntime({getEmailService,activeEmailProvider});if(recordRuntime(nucleusRuntime),resolvedOptions.liveMonitoring?.enabled){let liveBasePath=resolvedOptions.liveMonitoring.basePath||"/monitoring",liveStreamInterval=resolvedOptions.liveMonitoring.streamInterval||150;useRoutes(plugin,createLiveMonitoringRoutes({getService:()=>liveMonitoringService,getLifecycleRecorder:()=>lifecycleRecorder,logger:logger2,basePath:liveBasePath,streamInterval:liveStreamInterval,db,schemaTables}))}if(resolvedOptions.monitoring?.enabled&&resolvedOptions.monitoring.endpoints?.enabled){let monitoringEndpoints=resolvedOptions.monitoring.endpoints;useRoutes(plugin,createMonitoringRoutes({getService:()=>monitoringService,logger:logger2,endpoints:{enabled:!0,basePath:monitoringEndpoints.basePath||"/monitoring",allowRoles:monitoringEndpoints.allowRoles,stream:{enabled:monitoringEndpoints.stream?.enabled!==!1,path:monitoringEndpoints.stream?.path||"/stream",interval:monitoringEndpoints.stream?.interval||"5s"},snapshot:{enabled:monitoringEndpoints.snapshot?.enabled!==!1,path:monitoringEndpoints.snapshot?.path||"/snapshot"},history:{enabled:monitoringEndpoints.history?.enabled!==!1,path:monitoringEndpoints.history?.path||"/history",maxMinutes:monitoringEndpoints.history?.maxMinutes||60},alerts:{enabled:monitoringEndpoints.alerts?.enabled!==!1,path:monitoringEndpoints.alerts?.path||"/alerts"}},db,schemaTables}))}if(serverLogBuffer)useRoutes(plugin,createServerLogRoutes({buffer:serverLogBuffer,logger:logger2,basePath:serverLogsConfig?.basePath||resolvedOptions.monitoring?.endpoints?.basePath||"/monitoring",path:serverLogsConfig?.path||"/server-logs",allowRoles:serverLogsConfig?.allowRoles,streamEnabled:serverLogsConfig?.stream!==!1,clearEnabled:serverLogsConfig?.allowClear!==!1,db,schemaTables}));let bootStep=async(name2,run)=>{try{return await run()}catch(error3){logger2.error(`[Boot] Step "${name2}" failed \u2014 continuing in a degraded state rather than crashing`,{error:error3 instanceof Error?error3.message:String(error3)});return}},inboundGuard=createInboundGuard({maxRequestBodyBytes:resolvedOptions.security?.maxRequestBodyBytes});recordBootStep(async()=>{await bootStep("redis",()=>initiateRedisManager(resolvedOptions));let redis=getRedisManager();if(redis&&resolvedOptions.configManagement?.enabled)try{let{loadOverridesFromRedis:loadOverridesFromRedis2}=await Promise.resolve().then(() => (init_helpers4(),exports_helpers)),redisAdapter={read:async(key2)=>{let r=await redis.read(key2);return{success:r.success,data:r.success?r.data:null}}},{applied,ignored}=await loadOverridesFromRedis2(redisAdapter,resolvedOptions.appId||"nucleus",resolvedOptions);if(applied.length>0)logger2.info(`[ConfigManagement] Loaded ${applied.length} override(s) from Redis`,{sections:applied});if(ignored.length>0)logger2.warn(`[ConfigManagement] Ignored ${ignored.length} Redis override(s) naming no config section`,{sections:ignored})}catch(err){logger2.warn("[ConfigManagement] Failed to load overrides from Redis",{error:err instanceof Error?err.message:String(err)})}if(redis&&resolvedOptions.rateLimit?.enabled!==!1)rateLimiter=new RateLimiter({redis,logger:logger2,config:resolvedOptions.rateLimit||{}}),logger2.info(`[RateLimit] Enabled with strategy: ${resolvedOptions.rateLimit?.strategy||"sliding-window"}`);{let channels=resolvedOptions.notification?.channels;if(channels?.telegram?.enabled&&(!channels.telegram.botToken||!channels.telegram.chatId))logger2.warn("[Notification] telegram channel is enabled but botToken/chatId is missing \u2014 telegram deliveries will be skipped");if(channels?.webhook?.enabled&&!channels.webhook.url)logger2.warn("[Notification] webhook channel is enabled but url is missing \u2014 webhook deliveries will be skipped")}if(redis&&resolvedOptions.monitoring?.enabled){let monitoringDb=db,monitoringMetricsTable=schemaTables.monitoringMetrics,monitoringPersistenceEnabled=resolvedOptions.monitoring.persistence?.enabled!==!1,monitoringRetentionDays=resolvedOptions.monitoring.persistence?.retentionDays??30,lastMetricsCleanupAt=0,monitoringDbQuery=monitoringDb?async(sqlText)=>{return(await monitoringDb.execute(sql15.raw(sqlText))).rows}:void 0,monitoringLoadPeaks=monitoringDb&&monitoringPersistenceEnabled&&monitoringMetricsTable?async()=>{let t=monitoringMetricsTable;return(await monitoringDb.select({metricName:t.metricName,value:t.value,recordedAt:t.recordedAt,tags:t.tags}).from(t).where(eq70(t.metricType,"peak")).orderBy(desc7(t.value))).map((r)=>({metricName:String(r.metricName),value:Number(r.value??0),at:r.recordedAt?new Date(r.recordedAt).getTime():0,context:r.tags??void 0}))}:void 0;if(monitoringPersistenceEnabled&&monitoringDb&&!monitoringMetricsTable)logger2.warn("[Monitoring] monitoring.persistence is enabled but the monitoring_metrics table is missing from the generated schema \u2014 re-run nucleus-generate to add it");let monitoringFlushToDb=monitoringDb&&monitoringPersistenceEnabled&&monitoringMetricsTable?async(metrics)=>{if(metrics.length===0)return;let metricsTable=monitoringMetricsTable;await monitoringDb.insert(metricsTable).values(metrics.map((m)=>({metricType:m.metricType,metricName:m.metricName,value:m.value,tags:m.tags??null,recordedAt:new Date(m.timestamp)})));let nowMs=Date.now();if(nowMs-lastMetricsCleanupAt>86400000){lastMetricsCleanupAt=nowMs;let cutoff=new Date(nowMs-monitoringRetentionDays*24*60*60*1000);await monitoringDb.delete(metricsTable).where(and30(lt3(metricsTable.recordedAt,cutoff),ne5(metricsTable.metricType,"peak")))}}:void 0;monitoringService=new MonitoringService({redis,logger:logger2,getEmailService,config:resolvedOptions.monitoring,appId:resolvedOptions.appId,dbQuery:monitoringDbQuery,flushToDb:monitoringFlushToDb,loadPeaks:monitoringLoadPeaks}),monitoringService.start(),logger2.info("[Monitoring] Service started")}if(resolvedOptions.liveMonitoring?.enabled)liveMonitoringService=new LiveMonitoringService(resolvedOptions.liveMonitoring),liveMonitoringService.start(),logger2.info("[LiveMonitoring] Service started");let lifecycleRedis=getRedisManager()?.getDirectClient?.();if(lifecycleRedis){lifecycleRecorder=new LifecycleRecorder({backend:redisLifecycleBackend(lifecycleRedis),labels:{...process.env.HOSTNAME?{host:process.env.HOSTNAME}:{},...process.env.APP_VERSION?{version:process.env.APP_VERSION}:{}},logger:logger2}),lifecycleRecorder.claim();let beat=setInterval(()=>{(async()=>{let memory=(await monitoringService?.getLatestSnapshot?.())?.system?.memory;await lifecycleRecorder?.touch(memory?{rss:memory.rss??0,heapUsed:memory.heapUsed,external:memory.external??0,total:memory.total,usagePercent:memory.usagePercent,scope:memory.scope}:void 0)})()},LIFECYCLE_BEAT_MS);backgroundIntervals.push(beat),process.on("uncaughtException",(error3)=>{lifecycleRecorder?.recordFatal(error3,"uncaughtException"),logger2.error("[Lifecycle] Uncaught exception",error3)}),process.on("unhandledRejection",(reason)=>{lifecycleRecorder?.recordFatal(reason,"unhandledRejection"),logger2.error("[Lifecycle] Unhandled rejection",reason)})}let isConsumerModeOnStart=authentication?.mode==="consumer",consumerAllowedTableKeys=isConsumerModeOnStart&&entities?new Set(entities.map((e)=>e.table_name.replace(/_([a-z])/g,(_,c)=>c.toUpperCase()))):null;if(consumerAllowedTableKeys){let opts=resolvedOptions,verificationEnabled=opts.verification?.enabled===!0,notificationEnabled=opts.notification?.enabled===!0,auditEnabled=opts.audit?.enabled===!0,chatEnabled=opts.chat?.enabled===!0,storageEnabled=opts.storage?.enabled===!0,paymentEnabled=opts.payment?.enabled===!0,backupEnabled=opts.backup?.enabled===!0,monitoringPersistenceOn=resolvedOptions.monitoring?.enabled===!0&&resolvedOptions.monitoring?.persistence?.enabled!==!1,featureEnabled={verification:verificationEnabled,notification:notificationEnabled,audit:auditEnabled,chat:chatEnabled,storage:storageEnabled,payment:paymentEnabled,backup:backupEnabled,monitoring:monitoringPersistenceOn,secrets:resolvedOptions.secrets?.enabled===!0,domains:resolvedOptions.domains?.enabled===!0,"multi-tenant":isMultiTenant};for(let sysTable of SYSTEM_TABLES)if(sysTable.feature_set.some((f)=>{if(f==="authentication"||f==="authorization")return!1;if(!(f in featureEnabled))return logger2.warn(`[Schema] Consumer mode has no rule for feature "${f}" (table "${sysTable.table_name}") \u2014 `+"its table will NOT be synced. Add it to featureEnabled in Nucleus/index.ts."),!1;return featureEnabled[f]===!0})){let camelKey=sysTable.table_name.replace(/_([a-z])/g,(_,c)=>c.toUpperCase());consumerAllowedTableKeys.add(camelKey)}}if(db&&config.schema){let schemas=await import(__require("path").resolve(process.cwd(),config.schema)),auditLogsTable=schemaTables.auditLogs||schemas.auditLogs;if(audit?.enabled&&auditLogsTable)logger2.addAuditTransport(new DatabaseAuditTransport({db,table:auditLogsTable,enabled:!0,dedup:audit.dedup}));let{ensureSchemaExists:ensureSchemaExists2,applySchemaPush:applySchemaPush2}=await Promise.resolve().then(() => (init_schema(),exports_schema)),{reconcileMissingColumns:reconcileMissingColumns2,expectedFromTables:expectedFromTables2,readActualSchema:readActualSchema2,undeclaredTables:undeclaredTables2}=await Promise.resolve().then(() => (init_schemaReconcile(),exports_schemaReconcile));try{logger2.info(`Syncing schema to database (target: ${targetSchemaName})...`),await ensureSchemaExists2(db,targetSchemaName);let filteredTables={};try{filteredTables=Object.fromEntries(Object.entries(schemaTables).filter(([key2,v])=>{if(v===void 0||v===null)return!1;if(consumerAllowedTableKeys&&!consumerAllowedTableKeys.has(key2))return!1;if(typeof v==="object"&&v!==null)return Object.getOwnPropertySymbols(v).length>0||v._!==void 0;return!1}));let tableNames=Object.keys(filteredTables);if(logger2.info("[Schema] Tables to sync:",{tables:tableNames,count:tableNames.length,mode:isConsumerModeOnStart?"consumer":"full"}),!isConsumerModeOnStart){let usersTableDef=filteredTables.users;if(usersTableDef){let columnSymbols=Object.getOwnPropertyNames(usersTableDef).filter((k)=>!k.startsWith("_"));logger2.info("[Schema] Users table columns:",{columns:columnSymbols})}}let realExit=process.exit,push;try{process.exit=(code)=>{throw Error(`drizzle-kit called process.exit(${code??0}) during pushSchema \u2014 `+"suppressed so the app can keep booting")};let excluded=await(async()=>{try{let actual=await readActualSchema2((statement)=>db.execute(sql15.raw(statement)),targetSchemaName);return undeclaredTables2(expectedFromTables2(filteredTables),actual)}catch{return[]}})();if(excluded.length>0)logger2.info(`[Schema] Excluding tables the model does not declare, so the push is not asked to resolve a rename it cannot: ${excluded.join(", ")}`);let timeoutMs=database?.schemaPushTimeoutMs??120000;push=await withDeadline(pushSchema({schema:targetSchema,...filteredTables},db,[targetSchemaName],excluded.length>0?excluded.map((name2)=>`!${name2}`):void 0),timeoutMs,`pushSchema did not finish within ${timeoutMs}ms. drizzle-kit most likely hit its `+"interactive rename prompt, which cannot be answered without a TTY \u2014 it appears "+"when a push adds a new table while another table exists in the database but not in the schema. Drop the stale table, or split the change across two deploys.")}finally{process.exit=realExit}if(await applySchemaPush2(push,{schemaName:targetSchemaName,allowDataLoss:database?.allowDataLoss===!0,logger:logger2,execute:(statement)=>db.execute(sql15.raw(statement))}))logger2.info("[Schema] pushSchema completed successfully")}catch(pushError){let msg=pushError instanceof Error?pushError.message:String(pushError),repair=await reconcileMissingColumns2({db,schema:targetSchemaName,tables:filteredTables,logger:logger2,schemaObject:targetSchema});if(!repair||repair.applied>0||repair.plan.createdTables.length>0||repair.plan.missingTables.length>0||repair.plan.unsafe.length>0)logger2.error(`[Schema] pushSchema applied NOTHING: ${msg}`);else logger2.info(`[Schema] pushSchema applied nothing, and nothing was needed \u2014 the database already matches the model. (${msg})`)}logger2.info("[Schema] Schema sync completed",{schema:targetSchemaName})}catch(error3){logger2.error("[Schema] Schema sync failed",error3,{schema:targetSchemaName})}try{let{relaxSessionExpiryIfNever:relaxSessionExpiryIfNever2}=await Promise.resolve().then(() => (init_relaxSessionExpiry(),exports_relaxSessionExpiry)),{sql:sql16}=await import("drizzle-orm");await relaxSessionExpiryIfNever2({db,sql:sql16,schemaName:targetSchemaName,lifetimeSeconds:lifetimeSeconds(authentication?.sessionToken?.expiresIn,2592000),logger:logger2})}catch(error3){logger2.warn("[Schema] Session expiry relaxation skipped",{error:String(error3)})}if(secretsService)try{await secretsService.start(),logger2.info("[Secrets] Credential store ready",{storedCredentials:secretsService.size()})}catch(error3){logger2.error("[Secrets] Credential store failed to start \u2014 env and literal values still resolve",{error:error3 instanceof Error?error3.message:String(error3)})}if(logger2.info("[Database] Connection established"),await bootStep("multi-tenant schemas",async()=>{if(isMultiTenant&&db&&config.schema){let schemasForTenant={};try{let schemaPath=__require("path").resolve(process.cwd(),config.schema);logger2.info("[MultiTenant] Loading schema for tenant registry",{schemaPath}),schemasForTenant=await import(schemaPath),logger2.info("[MultiTenant] Schema loaded",{keys:Object.keys(schemasForTenant).slice(0,10),hasCreateAll:!!schemasForTenant.createAllTablesForSchema})}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.error("[MultiTenant] Failed to load schema for tenant registry",{error:msg})}let createAllFn=schemasForTenant.createAllTablesForSchema;if(createAllFn){let idpUrl=isConsumerModeOnStart?authentication?.idpUrl?String(process.env[authentication.idpUrl]||authentication.idpUrl):void 0:void 0;if(tenantRegistry=new TenantRegistry({db,logger:logger2,mainSchemaName:targetSchemaName,mainSchemaTables:schemaTables,mainSchemaRelations:schemaRelations,createAllTablesForSchema:createAllFn,createAllRelationsForSchema:schemasForTenant.createAllRelationsForSchema,appId:resolvedOptions.appId,authMode:authentication?.mode,tenantResolution:database?.tenantResolution||"both",tenantHeader:database?.tenantHeader||"x-tenant-id",redisCacheTtlSeconds:300,defaultTrustedSources:database?.defaultTrustedSources,idpUrl,allowDataLoss:database?.allowDataLoss===!0,onTenantProvisioned:resolvedOptions.authorization?.enabled&&!isConsumerModeOnStart?async(context)=>{let authConfig={...DEFAULT_AUTHORIZATION_CONFIG,...resolvedOptions.authorization};if(authConfig.autoSeedClaims&&db){let claimEntities=mergeEntitiesByName([...extractSchemaTableEntities(context.schemaTables),...SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),...effectiveConfigEntities(resolvedOptions.entities||[]),...config.systemTables||[],...resolvedOptions.authorization?.externalEntities||[]]);await seedClaims(db,context.schemaTables,context.schemaRelations,claimEntities,authConfig,logger2)}let seedConfig=resolvedOptions.authorization?.seed;if(seedConfig&&db){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));await runSeed2(db,context.schemaTables,seedConfig,logger2)}logger2.info(`[Authorization] New tenant schema seeded: ${context.schemaName}`)}:void 0}),isConsumerModeOnStart&&idpUrl){await tenantRegistry.initializeFromIdp(),logger2.info("[MultiTenant] Consumer mode: tenants fetched from IDP");let tenantSyncTimer=setInterval(()=>{tenantRegistry?.syncFromIdp().then((result)=>{if(result.added.length>0||result.removed.length>0)logger2.info(`[MultiTenant] Tenant sync: +${result.added.length} / -${result.removed.length} (total ${result.total})`)}).catch((err)=>{let msg=err instanceof Error?err.message:String(err);logger2.warn(`[MultiTenant] Tenant sync failed: ${msg}`)})},60000);trackInterval(tenantSyncTimer)}else await tenantRegistry.initialize();for(let schemaName of tenantRegistry.getAllSchemaNames()){if(schemaName===targetSchemaName)continue;let ctx=tenantRegistry.getSchemaContext(schemaName);if(ctx){await ensureSchemaExists2(db,schemaName);try{let tenantFilteredTables=Object.fromEntries(Object.entries(ctx.schemaTables).filter(([key2,v])=>{if(v===void 0||v===null)return!1;if(consumerAllowedTableKeys&&!consumerAllowedTableKeys.has(key2))return!1;if(typeof v==="object"&&v!==null)return Object.getOwnPropertySymbols(v).length>0||v._!==void 0;return!1})),tenantSchema=pgSchema2(schemaName),tenantPush=await pushSchema({schema:tenantSchema,...tenantFilteredTables},db,[schemaName]);if(await applySchemaPush2(tenantPush,{schemaName,allowDataLoss:database?.allowDataLoss===!0,logger:logger2,execute:(statement)=>db.execute(sql15.raw(statement))}))logger2.info(`[Schema] Tenant schema synced: ${schemaName}`)}catch(tenantPushError){let msg=tenantPushError instanceof Error?tenantPushError.message:String(tenantPushError);logger2.warn(`[Schema] Tenant schema sync warning for ${schemaName}: ${msg}`)}}}logger2.info(`[MultiTenant] Registry initialized with ${tenantRegistry.getAllSchemaNames().length} schemas`),logger2.info("[MultiTenant] Tenant registry ready, routes were pre-registered")}}}),resolvedOptions.authorization?.enabled&&!isConsumerModeOnStart){let authConfig={...DEFAULT_AUTHORIZATION_CONFIG,...resolvedOptions.authorization,godminEmail:resolveConfigCredential(resolvedOptions.authorization?.godminEmail),godminPassword:resolveConfigCredential(resolvedOptions.authorization?.godminPassword)};if(authConfig.autoSeedClaims){let schemaEntities=extractSchemaTableEntities(schemaTables),systemEntities=SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),configEntities=effectiveConfigEntities(resolvedOptions.entities||[]),externalEntities=resolvedOptions.authorization?.externalEntities||[],claimEntities=mergeEntitiesByName([...schemaEntities,...configEntities,...systemEntities,...config.systemTables||[],...externalEntities]);logger2.info("[Authorization] Seeding claims...",{schemaEntities:schemaEntities.length,systemEntities:systemEntities.length,configEntities:configEntities.length,externalEntities:externalEntities.length,totalEntities:claimEntities.length}),await seedClaims(db,schemaTables,schemaRelations,claimEntities,authConfig,logger2)}let discoveryConfig=resolvedOptions.authorization?.endpointDiscovery;if(discoveryConfig?.enabled&&(discoveryConfig.runOnBoot??!0)&&db)try{let{runEndpointDiscovery:runEndpointDiscovery2}=await Promise.resolve().then(() => (init_seed(),exports_seed)),discoveryResult=await runEndpointDiscovery2(db,schemaTables,discoveryConfig,logger2);logger2.info("[Authorization] Endpoint discovery completed",{services:discoveryResult.services})}catch(discoveryErr){logger2.error("[Authorization] Endpoint discovery failed",{error:discoveryErr instanceof Error?discoveryErr.message:String(discoveryErr)})}if(authConfig.godminEmail&&authConfig.godminPassword)logger2.info("[Authorization] Setting up godmin..."),await setupGodmin(db,schemaTables,authConfig,logger2);let seedConfig=resolvedOptions.authorization?.seed;if(seedConfig){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));logger2.info("[Authorization] Running custom seed...");let seedResult=await bootStep("authorization.seed",()=>runSeed2(db,schemaTables,seedConfig,logger2));if(seedResult)logger2.info("[Authorization] Custom seed completed",{rolesCreated:seedResult.rolesCreated,rolesExisting:seedResult.rolesExisting,claimsCreated:seedResult.claimsCreated,claimsExisting:seedResult.claimsExisting,assignmentsCreated:seedResult.assignmentsCreated,assignmentsExisting:seedResult.assignmentsExisting,assignmentsUpdated:seedResult.assignmentsUpdated})}let claimGuardsCfg=resolvedOptions.authorization?.claimGuards;if(claimGuardsCfg?.length){let{seedClaimGuards:seedClaimGuards2}=await Promise.resolve().then(() => (init_ClaimGuard(),exports_ClaimGuard));await bootStep("authorization.claimGuards",()=>seedClaimGuards2(db,schemaTables,claimGuardsCfg,logger2))}let jwtClaimsMode=resolvedOptions.authorization?.jwtClaimsMode||"embed",claimsCacheRedis=getRedisManager();if(jwtClaimsMode==="resolve"&&db&&claimsCacheRedis){let{ClaimsCache:ClaimsCache3}=await Promise.resolve().then(() => (init_ClaimsCache(),exports_ClaimsCache));claimsCache=new ClaimsCache3({prefix:resolvedOptions.authorization?.claimsCachePrefix||"nucleus:claims",redis:{get:async(key2)=>{let r=await claimsCacheRedis.read(key2);return r.success?r.data:null},set:async(key2,value2)=>{await claimsCacheRedis.create(key2,value2)},delete:async(key2)=>{await claimsCacheRedis.remove(key2)}},db,schemaTables,logger:logger2});let cacheInstance=claimsCache,cacheResult=await bootStep("authorization.claimsCache",()=>cacheInstance.buildCache());if(cacheResult)logger2.info("[Authorization] Claims cache built (resolve mode)",{version:cacheResult.version,roleCount:cacheResult.roleCount,totalMappings:cacheResult.totalMappings})}else if(jwtClaimsMode==="resolve"&&!claimsCacheRedis)logger2.warn("[Authorization] jwtClaimsMode=resolve requires Redis. Falling back to embed mode.");if(logger2.info("[Authorization] Enabled"),isMultiTenant&&tenantRegistry){let tenantSchemas=tenantRegistry.getAllSchemaNames().filter((name2)=>name2!==targetSchemaName);for(let tenantSchemaName of tenantSchemas){let tenantCtx=tenantRegistry.getSchemaContext(tenantSchemaName);if(!tenantCtx)continue;try{if(authConfig.autoSeedClaims){let tenantSchemaEntities=extractSchemaTableEntities(tenantCtx.schemaTables),tenantClaimEntities=mergeEntitiesByName([...tenantSchemaEntities,...SYSTEM_TABLES.map((table)=>normalizeSystemTable(table)),...effectiveConfigEntities(resolvedOptions.entities||[]),...config.systemTables||[],...resolvedOptions.authorization?.externalEntities||[]]);await seedClaims(db,tenantCtx.schemaTables,tenantCtx.schemaRelations,tenantClaimEntities,authConfig,logger2)}if(tenantCtx.tenant?.godAdminEmail&&authConfig.godminPassword)await setupGodmin(db,tenantCtx.schemaTables,{...authConfig,godminEmail:tenantCtx.tenant.godAdminEmail},logger2);if(seedConfig){let{runSeed:runSeed2}=await Promise.resolve().then(() => (init_SeedRunner(),exports_SeedRunner));await runSeed2(db,tenantCtx.schemaTables,seedConfig,logger2)}logger2.info(`[Authorization] Tenant schema seeded: ${tenantSchemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.warn(`[Authorization] Failed to seed tenant ${tenantSchemaName}: ${msg}`)}}logger2.info(`[Authorization] Multi-tenant seeding complete for ${tenantSchemas.length} schemas`)}}let sessionsTableRef=schemaTables.userSessions;if(!isConsumerModeOnStart&&sessionsTableRef&&resolvedOptions.authentication?.sessions?.enabled){let{lt:lt4}=await import("drizzle-orm"),expiredCount=await bootStep("auth.expiredSessionCleanup",()=>db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and30(eq70(sessionsTableRef.isActive,!0),lt4(sessionsTableRef.expiresAt,new Date))));if(expiredCount!==void 0)logger2.info("[AUTH] Expired sessions cleanup completed",{expiredCount});let sessionCleanupInterval=setInterval(async()=>{try{await db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and30(eq70(sessionsTableRef.isActive,!0),lt4(sessionsTableRef.expiresAt,new Date)));let approvalTtlMs=86400000,approvalCutoff=new Date(Date.now()-approvalTtlMs);await db.update(sessionsTableRef).set({isActive:!1,revokedAt:new Date,revokedReason:"approval_token_expired",approvalStatus:"rejected",approvalToken:null}).where(and30(eq70(sessionsTableRef.approvalStatus,"pending"),lt4(sessionsTableRef.approvalRequestedAt,approvalCutoff)))}catch(err){logger2.warn("[AUTH] Session cleanup failed",{error:err})}},3600000);trackInterval(sessionCleanupInterval)}if(isMultiTenant&&tenantRegistry&&resolvedOptions.authentication?.sessions?.enabled){let{lt:lt4}=await import("drizzle-orm"),tenantSchemaNames=tenantRegistry.getAllSchemaNames().filter((name2)=>name2!==targetSchemaName);for(let tenantSchemaName of tenantSchemaNames){let tenantCtx=tenantRegistry.getSchemaContext(tenantSchemaName);if(!tenantCtx)continue;let tenantSessionsTable=tenantCtx.schemaTables.userSessions||tenantCtx.schemaTables.user_sessions||tenantCtx.schemaTables.sessions;if(!tenantSessionsTable)continue;try{await db.update(tenantSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"expired"}).where(and30(eq70(tenantSessionsTable.isActive,!0),lt4(tenantSessionsTable.expiresAt,new Date))),logger2.info(`[AUTH] Tenant session cleanup completed: ${tenantSchemaName}`)}catch(err){let msg=err instanceof Error?err.message:String(err);logger2.warn(`[AUTH] Tenant session cleanup failed for ${tenantSchemaName}: ${msg}`)}}}}});let authMiddleware=async({request,set:set2,server})=>{let refusal=inboundGuard({request,set:set2,body:void 0,params:{},query:{}});if(refusal!==void 0)return refusal;let requestStartTime=Date.now(),requestSchemaTables=schemaTables;if(tenantRegistry){let tenantVettedClientIp=resolveClientIp(server?.requestIP?.(request)?.address??null,request.headers.get("x-forwarded-for")??request.headers.get("x-real-ip"),resolvedOptions.rateLimit?.trustedProxies??[]),tenantResult=tenantRegistry.resolveFromRequest(request,tenantVettedClientIp);if(tenantResult.resolved)requestSchemaTables=tenantResult.context.schemaTables,request.headers.set("x-tenant-schema",tenantResult.context.schemaName);else if(new URL(request.url).pathname!=="/health")return set2.status=tenantResult.statusCode,Response.json(withEnvelopeFlags({isSuccess:!1,message:tenantResult.error,status:tenantResult.statusCode,errors:[{message:tenantResult.error}],data:null}))}request.headers.set("x-request-start-time",String(requestStartTime));let requestId=randomUUID11();if(request.headers.set("x-request-id",requestId),set2.headers["x-request-id"]=requestId,resolvedOptions.security?.disableDefaultHeaders!==!0){set2.headers["X-Content-Type-Options"]="nosniff",set2.headers["X-Frame-Options"]="SAMEORIGIN",set2.headers["Referrer-Policy"]="strict-origin-when-cross-origin";let hstsMaxAge=resolvedOptions.security?.hstsMaxAge??15552000;if(hstsMaxAge>0)set2.headers["Strict-Transport-Security"]=`max-age=${hstsMaxAge}; includeSubDomains`}let url=new URL(request.url),pathname=url.pathname,method=request.method,query=url.search;if(csrfConfig.enabled){let csrfSecure=request.headers.get("x-forwarded-proto")==="https"||url.protocol==="https:"?"; Secure":"",issueCsrfCookie=()=>`${csrfConfig.cookieName}=${randomUUID11()}; Path=/; SameSite=Lax${csrfSecure}`,csrfCookies=parseCookies(request.headers.get("cookie"));if(requiresCsrf({method,cookies:csrfCookies,hasAuthorizationHeader:!!request.headers.get("authorization"),authCookieNames:csrfAuthCookieNames})&&!csrfTokenMatches(csrfCookies[csrfConfig.cookieName],request.headers.get(csrfConfig.headerName)))return set2.headers["Set-Cookie"]=issueCsrfCookie(),set2.status=403,Response.json(withEnvelopeFlags({isSuccess:!1,message:"CSRF token missing or invalid",status:403,errors:[{message:"CSRF token missing or invalid"}],data:null}));else if(!isStateChanging(method)&&!csrfCookies[csrfConfig.cookieName])set2.headers["Set-Cookie"]=issueCsrfCookie()}let socketIp=server?.requestIP?.(request)?.address??null,clientIp=resolveClientIp(socketIp,request.headers.get("x-forwarded-for")??request.headers.get("x-real-ip"),resolvedOptions.rateLimit?.trustedProxies??[]);request.headers.set("x-client-ip",clientIp);let userAgent=request.headers.get("user-agent")||"unknown";if(requestLogConfig.enabled&&requestLogConfig.logArrival&&!isRequestLogExcluded(pathname))logger2.log("debug",`\u2192 ${method} ${pathname}`,{requestId,method,path:pathname,query:requestLogConfig.includeQuery&&query?query:void 0,ip:clientIp,tenant:request.headers.get("x-tenant-schema")||void 0},void 0,void 0,"middleware.request");let tokens,parsedBody={},rawBodyText="";if(request.method!=="GET"&&request.method!=="HEAD")try{rawBodyText=await request.clone().text();let parsed=rawBodyText?JSON.parse(rawBodyText):{};parsedBody=parsed&&typeof parsed==="object"?parsed:{}}catch{parsedBody={}}let auditPayload=audit?.enabled?{id:randomUUID11(),user_id:"unknown",entity_name:pathname.split("/").filter(Boolean)[0]||"root",entity_id:null,operation_type:method,summary:"",old_values:{},new_values:parsedBody,ip_address:clientIp,user_agent:userAgent,timestamp:new Date().toISOString(),path:pathname,query}:null,isPublic=isPublicRoute(publicRoutes,pathname,method,{headers:request.headers,credentialed:()=>{let presented=parseTokenValuesFromHeaders(request.headers,tokenNames);return!!(presented.session_token||presented.access_token)}}),rateLimiterUserBudgetPending=!1,refuseRateLimited=(budget,retryAfter,subject)=>{if(set2.status=429,retryAfter)set2.headers["Retry-After"]=String(retryAfter);if(logger2.warn(`[RateLimit] Blocked ${pathname}: the ${budget} budget is spent (${budget==="address"?clientIp:subject||clientIp})`+(retryAfter?`, retry after ${retryAfter}s`:"")),monitoringService)monitoringService.recordRateLimitBlock();return new Response(JSON.stringify({isSuccess:!1,success:!1,message:"Too Many Requests",status:429,errors:[{message:"Too Many Requests"}],data:null,retryAfter}),{status:429,headers:{"Content-Type":"application/json"}})};if(rateLimiter){let routeCategory=isPublic?"public":"private",authType=resolveAuthType(pathname,resolvedOptions.authentication),category=authType?"auth":routeCategory,sharedPeer=!warnedSharedRateLimitBucket&&(resolvedOptions.rateLimit?.trustedProxies??[]).length===0&&(isNonDiscriminatingPeer(clientIp)?clientIp:peerDiversity.observe(clientIp));if(sharedPeer)warnedSharedRateLimitBucket=!0,logger2.warn(`[RateLimit] Every request so far has arrived from ${sharedPeer}, which cannot tell callers apart: every user shares ONE rate-limit bucket and one person can exhaust it for everybody. Set rateLimit.trustedProxies to the proxy address so X-Forwarded-For is honored, or raise rateLimit.privateRoutes/publicRoutes/authRoutes to values shared traffic cannot reach.`);rateLimiterUserBudgetPending=category==="private";let attempted=authType?readAttemptedIdentity(parsedBody,rawBodyText,request.headers.get("content-type")):void 0;if(authType&&!attempted&&(request.headers.get("content-type")||"").toLowerCase().includes("multipart/form-data"))try{let value2=(await request.clone().formData()).get("email");if(typeof value2==="string"&&value2.trim())attempted=value2}catch{}let rateLimitResult=await rateLimiter.check({ip:clientIp,endpoint:pathname,category,authType,identityResolved:authType?!!attempted:void 0}),limiter=rateLimiter,tightest=rateLimitResult,applyRateLimitHeaders=(result)=>{if(result.remaining>=0&&(tightest.remaining<0||result.remaining<tightest.remaining))tightest=result;for(let[key2,value2]of Object.entries(limiter.getHeaders(tightest)))set2.headers[key2]=value2};if(applyRateLimitHeaders(rateLimitResult),!rateLimitResult.allowed)return refuseRateLimited("address",rateLimitResult.retryAfter);if(attempted){let perIdentity=await rateLimiter.check({ip:clientIp,endpoint:pathname,category,authType,identity:attempted});if(applyRateLimitHeaders(perIdentity),!perIdentity.allowed)return refuseRateLimited("account",perIdentity.retryAfter,"the account being attempted")}}if(pathname==="/health"||pathname==="/health/ready")return;if(authentication?.enabled&&!isPublic){let apiKeyRaw=extractApiKeyFromHeader(request.headers),apiKeysTableRef=requestSchemaTables.apiKeys;if(apiKeyRaw&&authentication.apiKeys?.enabled&&apiKeysTableRef&&db){let keyHash=hashApiKey(apiKeyRaw),apiKeyRecord=(await db.select().from(apiKeysTableRef).where(eq70(apiKeysTableRef.keyHash,keyHash)).limit(1))[0];if(!apiKeyRecord)return set2.status=401,logger2.traceSync({message:"Invalid API key",level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,"Invalid API key")}),Error("Invalid API key");let validation=validateApiKeyRecord(apiKeyRecord);if(!validation.valid)return set2.status=401,logger2.traceSync({message:`API key rejected: ${validation.reason}`,level:"warn",context:{path:pathname,method,keyId:apiKeyRecord.id},audit:toAudit(auditPayload,`API key rejected: ${validation.reason}`)}),Error(validation.reason);let apiKeyUserId=apiKeyRecord.userId,apiKeyUserData;{let ksTable=requestSchemaTables.users;if(ksTable&&db){apiKeyUserData=(await db.select().from(ksTable).where(eq70(ksTable.id,apiKeyUserId)).limit(1))[0];let{evaluateAccountState:evaluateAccountState2}=await Promise.resolve().then(() => exports_accountState),ksState=apiKeyUserData?evaluateAccountState2(apiKeyUserData):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!ksState.allowed)return set2.status=401,logger2.traceSync({message:`API key rejected: account ${ksState.reason}`,level:"warn",context:{path:pathname,method,keyId:apiKeyRecord.id},audit:toAudit(auditPayload,`API key rejected: account ${ksState.reason}`,{userId:apiKeyUserId})}),Error(ksState.message)}}let keyAllowedRoles=apiKeyRecord.allowedRoles||[],keyAllowedClaims=apiKeyRecord.allowedClaims||[],effectiveRoles=keyAllowedRoles,effectiveClaims=keyAllowedClaims,apiKeyClaimScopes={},userRolesTable=requestSchemaTables.userRoles,rolesTable=requestSchemaTables.roles,roleClaimsTable=requestSchemaTables.roleClaims,claimsTable=requestSchemaTables.claims;if(userRolesTable&&rolesTable){let currentUserRoles=(await db.select({name:rolesTable.name}).from(userRolesTable).innerJoin(rolesTable,eq70(rolesTable.id,userRolesTable.roleId)).where(eq70(userRolesTable.userId,apiKeyUserId))).map((r)=>r.name).filter((n)=>n!==void 0);effectiveRoles=intersectPermissions(currentUserRoles,keyAllowedRoles)}if(userRolesTable&&roleClaimsTable&&claimsTable){let userClaimRows=await db.select({action:claimsTable.action,scope:roleClaimsTable.scope}).from(userRolesTable).innerJoin(roleClaimsTable,eq70(roleClaimsTable.roleId,userRolesTable.roleId)).innerJoin(claimsTable,eq70(claimsTable.id,roleClaimsTable.claimId)).where(eq70(userRolesTable.userId,apiKeyUserId)),currentUserClaims=[...new Set(userClaimRows.map((r)=>r.action).filter((a)=>a!==void 0))];effectiveClaims=intersectPermissions(currentUserClaims,keyAllowedClaims);let effectiveClaimSet=new Set(effectiveClaims),apiScopedRows=userClaimRows.filter((r)=>typeof r.action==="string"&&effectiveClaimSet.has(r.action)).map((r)=>({action:r.action,scope:r.scope??null}));if(apiScopedRows.some((r)=>!!r.scope)){let{claimScopes,dropped}=resolveClaimScopes(apiScopedRows,apiKeyUserData,logger2);if(apiKeyClaimScopes=claimScopes,dropped.length>0){let droppedSet=new Set(dropped);effectiveClaims=effectiveClaims.filter((a)=>!droppedSet.has(a))}}}if(db.update(apiKeysTableRef).set({lastUsedAt:new Date,lastUsedIp:clientIp,usageCount:apiKeyRecord.usageCount+1}).where(eq70(apiKeysTableRef.id,apiKeyRecord.id)).catch(()=>{}),effectiveRoles=effectiveRoles.filter((r)=>r!==GODMIN_ROLE_NAME),request.headers.set("x-user-id",apiKeyUserId),request.headers.set("x-auth-type","api_key"),request.headers.set("x-api-key-id",apiKeyRecord.id),request.headers.set("x-api-key-owner-type",apiKeyRecord.ownerType||"personal"),effectiveRoles.length>0)request.headers.set("x-user-roles",encodeHeaderList(effectiveRoles));if(effectiveClaims.length>0)request.headers.set("x-user-claims",encodeHeaderList(effectiveClaims));{let apiEncodedScopes=encodeClaimScopesHeader(apiKeyClaimScopes);if(apiEncodedScopes)request.headers.set("x-user-claim-scopes",apiEncodedScopes)}logger2.info("[AUTH] API key authenticated",{userId:apiKeyUserId,keyId:apiKeyRecord.id,ownerType:apiKeyRecord.ownerType,path:pathname,method,effectiveRoles:effectiveRoles.length,effectiveClaims:effectiveClaims.length});return}if(!authentication.accessToken?.secret)return set2.status=500,logger2.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:pathname,method},audit:toAudit(auditPayload,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(authentication.mode==="consumer"){tokens=parseTokenValuesFromHeaders(request.headers,tokenNames);let jwtResult=verifyJWT(tokens.access_token||"",envResolved.accessTokenSecret||"",{issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience});if(!jwtResult.valid)return set2.status=401,logger2.traceSync({message:"Invalid or missing access token",level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,"Invalid or missing access token",{userId:decodeUnverifiedSubject(tokens.access_token)})}),Error("Unauthenticated");let consumerBinding=verifyTenantBinding(jwtResult.payload[TENANT_CLAIM],request.headers.get("x-tenant-schema"),resolvedOptions.authentication?.tenantBinding??"lenient");if(!consumerBinding.ok)return set2.status=401,logger2.traceSync({message:"Access token tenant binding failed",level:"warn",context:{path:pathname,method,reason:consumerBinding.reason},audit:toAudit(auditPayload,"Access token tenant binding failed",{userId:decodeUnverifiedSubject(tokens.access_token)})}),Error("Unauthenticated");let userId=jwtResult.payload.sub,roles=jwtResult.payload.roles,claimsFromToken=jwtResult.payload.claims;if(request.headers.set("x-access-token",tokens.access_token||""),request.headers.set("x-user-id",userId||""),roles&&roles.length>0)request.headers.set("x-user-roles",encodeHeaderList(roles));if(claimsFromToken&&claimsFromToken.length>0)request.headers.set("x-user-claims",encodeHeaderList(claimsFromToken));{let encodedScopes=encodeClaimScopesHeader(jwtResult.payload.claimScopes);if(encodedScopes)request.headers.set("x-user-claim-scopes",encodedScopes)}}else{if(!authentication.refreshToken?.secret||!authentication.sessionToken?.secret)return set2.status=500,logger2.traceSync({message:"Authentication secrets not defined",level:"error",context:{path:pathname,method},audit:toAudit(auditPayload,"Authentication secrets not defined")}),Error("One or more authentication secrets are not defined");if(tokens=parseTokenValuesFromHeaders(request.headers,tokenNames),!tokens.session_token)return set2.status=401,logger2.traceSync({message:"No session token",level:"debug",context:{path:pathname,method},audit:toAudit(auditPayload,"No session token")}),Error("Unauthenticated");let sessionData=await readSession({sessionId:tokens.session_token});if(!sessionData)return set2.status=401,logger2.traceSync({message:"Invalid session",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token},audit:toAudit(auditPayload,"Invalid session")}),Error("Unauthenticated");let sessionsTableCheck=requestSchemaTables.userSessions;if(sessionsTableCheck&&db){let session=(await db.select().from(sessionsTableCheck).where(eq70(sessionsTableCheck.id,tokens.session_token)).limit(1))[0],revokedAtVal=session?.revokedAt,isRevoked=revokedAtVal!=null&&!(typeof revokedAtVal==="object"&&!(revokedAtVal instanceof Date)&&Object.keys(revokedAtVal).length===0);if(!session||session.isActive===!1||isRevoked)return set2.status=401,logger2.traceSync({message:"Session revoked or inactive",level:"warn",context:{path:pathname,method,sessionId:tokens.session_token,isActive:session?.isActive,revokedAt:session?.revokedAt},audit:toAudit(auditPayload,"Session revoked",{userId:sessionData.userId??null})}),Error("Session has been revoked");if(session.expiresAt&&new Date(session.expiresAt)<new Date)return set2.status=401,logger2.traceSync({message:"Session expired",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token,expiresAt:session.expiresAt},audit:toAudit(auditPayload,"Session expired",{userId:sessionData.userId??null})}),Error("Session has expired")}let accountTable=requestSchemaTables.users;if(accountTable&&db&&sessionData.userId){let account=(await db.select().from(accountTable).where(eq70(accountTable.id,sessionData.userId)).limit(1))[0];if(account?.isActive===!1)return set2.status=401,logger2.traceSync({message:"Account deactivated",level:"warn",context:{path:pathname,method,userId:sessionData.userId},audit:toAudit(auditPayload,"Account deactivated",{userId:sessionData.userId??null})}),Error("Account is not active");if(!account)logger2.traceSync({message:"Session user row did not resolve; account state unchecked",level:"warn",context:{path:pathname,method,userId:sessionData.userId}})}if(isIdleExpired({lastActiveAt:sessionData.lastActiveAt,inactivityTimeout:authentication.sessions?.inactivityTimeout}))return set2.status=401,logger2.traceSync({message:"Session inactive timeout",level:"debug",context:{path:pathname,method,sessionId:tokens.session_token,lastActiveAt:sessionData.lastActiveAt},audit:toAudit(auditPayload,"Session inactive timeout",{userId:sessionData.userId??null})}),Error("Session expired due to inactivity");updateLastActiveAt(tokens.session_token).catch(()=>{});let sessionsTableRef=requestSchemaTables.userSessions;if(sessionsTableRef&&db)db.update(sessionsTableRef).set({lastActivityAt:new Date}).where(eq70(sessionsTableRef.id,tokens.session_token)).catch(()=>{});let jwtResult=verifyJWT(tokens.access_token||"",envResolved.accessTokenSecret||"",{issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience}),isAccessTokenValid=tokens.access_token?jwtResult.valid:!1,isRefreshTokenValid=tokens.refresh_token?verifyJWT(tokens.refresh_token,envResolved.refreshTokenSecret||"",{issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience}).valid:!1;if(!isAccessTokenValid&&isRefreshTokenValid&&tokens.refresh_token&&sessionData.rememberMe===!0){let killSwitchUsersTable=requestSchemaTables.users;if(db&&killSwitchUsersTable){let ksUser=(await db.select().from(killSwitchUsersTable).where(eq70(killSwitchUsersTable.id,sessionData.userId)).limit(1))[0],{evaluateAccountState:evaluateAccountState2}=await Promise.resolve().then(() => exports_accountState),ksState=ksUser?evaluateAccountState2(ksUser):{allowed:!1,reason:"inactive",message:"Account is not active"};if(!ksState.allowed)return set2.status=401,logger2.traceSync({message:`Silent refresh blocked - account ${ksState.reason}`,level:"warn",context:{path:pathname,method},audit:toAudit(auditPayload,`Silent refresh blocked - account ${ksState.reason}`,{userId:sessionData.userId??null})}),Error(ksState.message)}let refreshRoles=[],refreshClaims=[],refreshClaimScopes={},refreshUserRolesTable=requestSchemaTables.userRoles,refreshRolesTable=requestSchemaTables.roles,refreshRoleClaimsTable=requestSchemaTables.roleClaims,refreshClaimsTable=requestSchemaTables.claims;if(db&&refreshUserRolesTable&&refreshRolesTable)try{let{fetchUserRolesAndClaims:fetchUserRolesAndClaims2}=await Promise.resolve().then(() => (init_fetchUserRolesAndClaims(),exports_fetchUserRolesAndClaims)),rc=await fetchUserRolesAndClaims2(db,sessionData.userId,{usersTable:killSwitchUsersTable??null,sessionsTable:null,userRolesTable:refreshUserRolesTable,rolesTable:refreshRolesTable,roleClaimsTable:refreshRoleClaimsTable,claimsTable:refreshClaimsTable,oauthAccountsTable:void 0,apiKeysTable:void 0,schemaTables:requestSchemaTables});refreshRoles=rc.roles,refreshClaims=rc.claims,refreshClaimScopes=rc.claimScopes}catch{}let refreshResult=await refreshAccessTokenWithLock(sessionData.userId,sessionData.id,()=>signNewAccessToken({refreshTokenId:tokens.refresh_token,options:resolvedOptions,sessionData,roles:refreshRoles.length>0?refreshRoles:void 0,claims:refreshClaims.length>0?refreshClaims:void 0,claimScopes:refreshClaimScopes,tenant:request.headers.get("x-tenant-schema")??void 0,resolveMode:resolvedOptions.authorization?.jwtClaimsMode==="resolve"&&!!claimsCache}));if(refreshResult.success&&refreshResult.accessToken){tokens.access_token=refreshResult.accessToken;let rawDomain=authentication.cookieDomain,resolvedDomainRaw=rawDomain?process.env[rawDomain]??rawDomain:void 0,resolvedDomain=resolvedDomainRaw==="localhost"||resolvedDomainRaw===".localhost"?void 0:resolvedDomainRaw,domainPart=resolvedDomain?`; Domain=${resolvedDomain}`:"",bufferSeconds=authentication.cookieMaxAgeBufferSeconds??0,maxAge=Math.max(0,parseTimeToSeconds2(authentication.accessToken.expiresIn??"15m")-bufferSeconds),securePart=!resolvedDomain?"":"; Secure",cookieValue=`${tokenNames.access_token}=${refreshResult.accessToken}; Path=/; HttpOnly; SameSite=Lax${securePart}; Max-Age=${maxAge}${domainPart}`;set2.headers["Set-Cookie"]=cookieValue}}if(jwtResult.valid){let fullBinding=verifyTenantBinding(jwtResult.payload[TENANT_CLAIM],request.headers.get("x-tenant-schema"),resolvedOptions.authentication?.tenantBinding??"lenient");if(!fullBinding.ok)return set2.status=401,logger2.traceSync({message:"Access token tenant binding failed",level:"warn",context:{path:pathname,method,reason:fullBinding.reason},audit:toAudit(auditPayload,"Access token tenant binding failed",{userId:jwtResult.payload.sub??null})}),Error("Unauthenticated")}if(jwtResult.valid&&jwtResult.payload.sub&&String(jwtResult.payload.sub)!==String(sessionData.userId))return set2.status=401,logger2.traceSync({message:"Access token subject does not match session",level:"warn",context:{path:pathname,method,sessionUserId:sessionData.userId,tokenSub:jwtResult.payload.sub},audit:toAudit(auditPayload,"Access token/session subject mismatch",{userId:sessionData.userId??null})}),Error("Unauthenticated");let userId=jwtResult.valid?jwtResult.payload.sub:sessionData.userId,roles=jwtResult.valid?jwtResult.payload.roles:void 0,claimsFromToken=jwtResult.valid?jwtResult.payload.claims:void 0;if(!jwtResult.valid&&userId&&db){let{userRoles:sessionUserRolesTable,roles:sessionRolesTable}=requestSchemaTables;if(sessionUserRolesTable&&sessionRolesTable)try{let{fetchUserRolesAndClaims:fetchUserRolesAndClaims2}=await Promise.resolve().then(() => (init_fetchUserRolesAndClaims(),exports_fetchUserRolesAndClaims)),sessionRc=await fetchUserRolesAndClaims2(db,userId,{usersTable:requestSchemaTables.users??null,sessionsTable:null,userRolesTable:sessionUserRolesTable,rolesTable:sessionRolesTable,roleClaimsTable:requestSchemaTables.roleClaims,claimsTable:requestSchemaTables.claims,oauthAccountsTable:void 0,apiKeysTable:void 0,schemaTables:requestSchemaTables});if(sessionRc.roles.length>0)roles=sessionRc.roles;if(sessionRc.claims.length>0)claimsFromToken=sessionRc.claims}catch(err){logger2.traceSync({message:"Session-authenticated role resolution failed",level:"warn",context:{path:pathname,method,error:String(err)}})}}if(!claimsFromToken?.length&&claimsCache&&roles&&roles.length>0)try{let resolvedClaims=await claimsCache.resolveClaimsForRoles(roles);if(resolvedClaims.length>0)claimsFromToken=resolvedClaims}catch{}if(userId&&db&&authentication.cohorts?.enabled){let mwUsersTable=requestSchemaTables.users;if(mwUsersTable)try{let mwCohortId=(await db.select().from(mwUsersTable).where(eq70(mwUsersTable.id,userId)).limit(1))[0]?.cohortId;if(mwCohortId){let mwCohortsTable=requestSchemaTables.userCohorts??requestSchemaTables.user_cohorts;if(mwCohortsTable){let mwExpiresAt=(await db.select().from(mwCohortsTable).where(eq70(mwCohortsTable.id,mwCohortId)).limit(1))[0]?.expiresAt;if(mwExpiresAt&&new Date(mwExpiresAt)<new Date)return set2.status=403,logger2.traceSync({message:"Cohort expired - access denied",level:"warn",context:{path:pathname,method,userId,cohortId:mwCohortId},audit:toAudit(auditPayload,"Cohort expired",{userId:userId??null})}),Error("Your access has expired. Please contact your administrator.")}}}catch{}}if(request.headers.set("x-access-token",tokens.access_token||""),request.headers.set("x-refresh-token",tokens.refresh_token||""),request.headers.set("x-session-id",tokens.session_token||""),request.headers.set("x-user-id",userId||""),roles&&roles.length>0)request.headers.set("x-user-roles",encodeHeaderList(roles));if(claimsFromToken&&claimsFromToken.length>0)request.headers.set("x-user-claims",encodeHeaderList(claimsFromToken));{let encodedScopes=encodeClaimScopesHeader(jwtResult.valid?jwtResult.payload.claimScopes:void 0);if(encodedScopes)request.headers.set("x-user-claim-scopes",encodedScopes)}}}if(rateLimiter&&!isPublic&&rateLimiterUserBudgetPending){let resolvedUserId=request.headers.get("x-user-id");if(resolvedUserId){let perUser=await rateLimiter.check({ip:clientIp,userId:resolvedUserId,endpoint:pathname,category:"private"});if(perUser.remaining>=0)for(let[key2,value2]of Object.entries(rateLimiter.getHeaders(perUser)))set2.headers[key2]=value2;if(!perUser.allowed)return refuseRateLimited("user",perUser.retryAfter,`user ${resolvedUserId}`)}}},afterHandler=({request,set:set2})=>{let afterUrl=new URL(request.url),afterStatus=typeof set2.status==="number"?set2.status:200,afterStartStr=request.headers.get("x-request-start-time"),afterDuration=afterStartStr?Date.now()-parseInt(afterStartStr,10):0;if(requestLogConfig.enabled&&!isRequestLogExcluded(afterUrl.pathname)){let isSlow=afterDuration>=requestLogConfig.slowThresholdMs,level=afterStatus>=500?"error":afterStatus>=400||isSlow?"warn":"info";logger2.log(level,`\u2190 ${request.method} ${afterUrl.pathname} ${afterStatus} (${afterDuration}ms)`,{requestId:request.headers.get("x-request-id")||void 0,method:request.method,path:afterUrl.pathname,query:requestLogConfig.includeQuery&&afterUrl.search?afterUrl.search:void 0,statusCode:afterStatus,durationMs:afterDuration,slow:isSlow||void 0,userId:request.headers.get("x-user-id")||void 0,authType:request.headers.get("x-auth-type")||void 0,tenant:request.headers.get("x-tenant-schema")||void 0,ip:request.headers.get("x-forwarded-for")?.split(",")[0]?.trim()||request.headers.get("x-real-ip")||void 0},void 0,void 0,"middleware.request")}if(monitoringService){let startTimeStr=request.headers.get("x-request-start-time"),startTime=startTimeStr?parseInt(startTimeStr,10):Date.now(),responseTimeMs=Date.now()-startTime,url=new URL(request.url),status=typeof set2.status==="number"?set2.status:200;monitoringService.recordRequest({endpoint:url.pathname,method:request.method,status,responseTimeMs,isError:status>=500,errorType:status>=500?"server_error":status>=400?"client_error":void 0})}if(liveMonitoringService){let url=new URL(request.url),headersObj=redactSensitiveHeaders(request.headers);liveMonitoringService.recordRequest({path:url.pathname,method:request.method,timestamp:Date.now(),headers:headersObj})}};recordAdapterStep((app)=>{app.onRequest(authMiddleware).onAfterHandle(afterHandler)});let errorResponder=(ctx)=>{let{set:set2,code,error:error3,request}=ctx,status=statusOfError(code,error3),message="Internal Server Error",pgCode,clientSafe=!1;if(error3 instanceof Error){let cause=error3.cause;if(pgCode=cause?.code,pgCode==="23505")message="A record with this value already exists",clientSafe=!0,status=409;else if(pgCode==="23503"){let detail=String(cause?.detail??"");if(detail.includes("is still referenced from")){let referencing=detail.match(/is still referenced from table "([^"]+)"/)?.[1];message=referencing?`Cannot delete: records in '${referencing}' still reference this one. Remove them first.`:"Cannot delete: another record still references this one",status=409}else message="Referenced record does not exist",status=400;clientSafe=!0}else if(pgCode==="23502")message=`Missing required field: ${cause?.column||"a required field is empty"}`,clientSafe=!0,status=400;else if(pgCode==="23514")message=String(cause?.message??"A database constraint refused this value"),clientSafe=!0,status=400;else if(pgCode==="22003")message="A value is out of range for its field",clientSafe=!0,status=400;else if(pgCode==="22P02")message=cause?.routine==="string_to_uuid"?"Invalid ID format":"Invalid data format",clientSafe=!0,status=400;else if(pgCode)message=`Database error (${pgCode}): ${cause?.detail||cause?.message||error3.message}`;else if(code==="VALIDATION")message=describeValidationError(error3)??error3.message,clientSafe=!0;else message=error3.message,clientSafe=status<500}try{let errUrl=new URL(request.url),errStartStr=request.headers.get("x-request-start-time");logger2.log(status>=500?"error":"warn",`\u2716 ${request.method} ${errUrl.pathname} ${status}: ${message}`,{requestId:request.headers.get("x-request-id")||void 0,method:request.method,path:errUrl.pathname,statusCode:status,elysiaCode:typeof code==="string"?code:void 0,pgCode,durationMs:errStartStr?Date.now()-parseInt(errStartStr,10):void 0,userId:request.headers.get("x-user-id")||void 0,tenant:request.headers.get("x-tenant-schema")||void 0},status>=500?error3:void 0)}catch(logErr){logger2.error("Failed to log request error",logErr)}set2.status=status;let clientMessage=clientSafe?message:"Internal Server Error",requestId=request.headers.get("x-request-id")||void 0;if(requestId)set2.headers["x-request-id"]=requestId;return Response.json(withEnvelopeFlags({isSuccess:!1,message:clientMessage,status,requestId,errors:[{message:clientMessage}],data:null}))};recordAdapterStep((app)=>{app.onError(errorResponder)});let featureAdminRoles={};for(let[feature,section]of Object.entries(resolvedOptions)){if(!section||typeof section!=="object")continue;let roles=section.adminRoles;if(!Array.isArray(roles))continue;let named=roles.filter((role)=>typeof role==="string"&&role.length>0);if(named.length>0)featureAdminRoles[feature]=named}let onEntityWritten=resolvedOptions.verification?.enabled&&db?(info)=>{let ctx=tenantRegistry?.getSchemaContext(info.request.headers.get("x-tenant-schema")??""),{buildVerificationServices:buildVerificationServices2}=(init_buildServices(),__toCommonJS(exports_buildServices)),{verificationService:svc}=buildVerificationServices2({db,schemaTables:ctx?.schemaTables??schemaTables,config:resolvedOptions.verification,notificationConfig:resolvedOptions.notification,logger:logger2,getEmailService});svc.startIfTriggered({entity_name:info.entityName,entity_id:info.entityId,operation:info.operation,started_by:info.userId}).catch((err)=>{logger2.error(`[Verification] trigger after ${info.operation} of ${info.entityName}:${info.entityId} failed: ${String(err)}`)})}:void 0;logger2.info("Creating routes for entities"),createEntityRoutes(plugin,{onEntityWritten,db,schemaTables,schemaRelations,entities,logger:logger2,databaseUrl:envResolved.databaseUrl,dbPool,storage:resolvedOptions.storage,cdnMedia:{transform:mergeTransformConfig(resolvedOptions.storage?.cdn?.transform),video:mergeVideoConfig(resolvedOptions.storage?.cdn?.video),pdf:mergePdfConfig(resolvedOptions.storage?.cdn?.pdf)},authorization:resolvedOptions.authorization,featureAdminRoles,accountLinks:authentication?.accountLinks,authMode:authentication?.mode,idpUrl:authentication?.idpUrl?process.env[authentication.idpUrl]||authentication.idpUrl:void 0,isEmailServiceAvailable:()=>!!getEmailService()?.isAvailable(),onRoleChanged:({userId:subjectId,roleName,assigned})=>{if(!db)return;let service=new NotificationService({db,schemaTables,config:resolvedOptions.notification??{},logger:logger2,getEmailService}),title=assigned?`New role: ${roleName}`:`Role removed: ${roleName}`,body=assigned?`You have been given the "${roleName}" role in the portal. New sections will appear in your menu.`:`Your "${roleName}" role in the portal has been removed. The sections it opened will no longer appear.`;service.send({user_id:subjectId,title,body,type:"system",source:"authorization",channels:["portal","email"]}).catch(()=>{})},tenantRegistry,getTenantRegistry:()=>tenantRegistry,claimsCache});let isConsumerMode=authentication?.mode==="consumer";if(isMultiTenant&&!isConsumerMode)createTenantRoutes(plugin,{getDb:()=>db,logger:logger2,getTenantRegistry:()=>tenantRegistry,schemaName:targetSchemaName}),logger2.info("[MultiTenant] Tenant routes pre-registered (handlers check runtime readiness)");else if(isMultiTenant&&isConsumerMode){let routePostTenantsRefresh=defineRoute({method:"POST",path:"/tenants/refresh",handler:async(ctx)=>{if(!tenantRegistry||!tenantRegistry.isConsumerMode())return ctx.set.status=503,{success:!1,message:"Tenant registry not ready"};try{return{success:!0,data:await tenantRegistry.syncFromIdp()}}catch(err){let msg=err instanceof Error?err.message:String(err);return ctx.set.status=500,{success:!1,message:`Tenant sync failed: ${msg}`}}}});mountRoutes(plugin,[{routes:[routePostTenantsRefresh]}]),logger2.info("[MultiTenant] Consumer tenant refresh route registered (/tenants/refresh)")}let domainServices=null;if(resolvedOptions.domains?.enabled){if(domainServices=createDomainServices({options:resolvedOptions,logger:logger2,getDb:()=>db,getTenantRegistry:()=>tenantRegistry}),domainServices)createDomainRoutes(plugin,{getDomainService:()=>domainServices?.domainService??null,getRegistrationService:()=>domainServices?.registrationService??null,logger:logger2,basePath:resolvedOptions.domains.basePath||"/domains",resolveTenantIdForSchema:(schema3)=>schema3&&tenantRegistry?tenantRegistry.getTenantBySchemaName(schema3)?.id??null:null}),logger2.info("[Domains] Custom domain routes registered",{provider:domainServices.domainService.config.provider,basePath:resolvedOptions.domains.basePath||"/domains"})}if(authentication?.enabled&&!isConsumerMode&&db){let resolveTableForTenant=(tableName,reqSchemaName)=>{if(reqSchemaName&&tenantRegistry){let ctx=tenantRegistry.getSchemaContext(reqSchemaName);if(ctx?.schemaTables[tableName])return ctx.schemaTables[tableName]}return schemaTables[tableName]},usersTable=schemaTables.users,sessionsTable=schemaTables.userSessions||schemaTables.user_sessions||schemaTables.sessions;if(!sessionsTable&&authentication.sessions?.enabled)logger2.warn("[AUTH] sessions is enabled but user_sessions table not found in schema. Disabling sessions.");if(usersTable){await initiateRedisManager(resolvedOptions);let{createAuthRoutes:createAuthRoutes2}=(init_auth(),__toCommonJS(exports_auth)),{signJWT:signJWT2,verifyJWT:verifyJWT3}=(init_JWT(),__toCommonJS(exports_JWT)),{generateSession:generateSession2,deleteSession:deleteSession2}=(init_SessionStore(),__toCommonJS(exports_SessionStore));createAuthRoutes2(plugin,{authConfig:{db,logger:logger2,usersTable,sessionsTable,userRolesTable:schemaTables.userRoles,rolesTable:schemaTables.roles,roleClaimsTable:schemaTables.roleClaims,claimsTable:schemaTables.claims,authentication:{enabled:authentication.enabled,mode:authentication.mode,get defaultRole(){return resolvedOptions.authentication?.defaultRole||process.env.AUTH_DEFAULT_ROLE},get defaultRoles(){return resolvedOptions.authentication?.defaultRoles},cookieDomain:resolvedOptions.authentication?.cookieDomain,get trustedAppOrigins(){return trustedAppOrigins()},emailExemptDomains:authentication?.emailExemptDomains,passwordPolicy:authentication?.passwordPolicy,emailVerificationTemplates:authentication?.register?.emailVerification?.templates,accessToken:authentication.accessToken,refreshToken:authentication.refreshToken,sessionToken:authentication.sessionToken,rememberMe:authentication.rememberMe,deviceTrust:authentication.sessions?.deviceTrust}},features:{login:authentication.login,register:authentication.register,logout:authentication.logout,refresh:authentication.refresh,passwordReset:withResolvedRedirects(authentication.passwordReset,["redirectUrl"]),passwordChange:authentication.passwordChange,passwordSet:authentication.passwordSet,sessions:withResolvedRedirects(authentication.sessions,["approvalRedirectUrl"]),magicLink:withResolvedRedirects(authentication.magicLink,["redirectUrl"]),me:authentication.me||{enabled:!0,route:"/auth/me"},invite:withResolvedRedirects(authentication.invite,["redirectUrl"]),captcha:authentication.captcha,oauth:authentication.oauth?.enabled&&envResolved.oauthProviders?{...withResolvedRedirects(authentication.oauth,["successRedirectUrl","errorRedirectUrl"]),providers:liveOAuthProviders(envResolved.oauthProviders)}:void 0,apiKeys:authentication.apiKeys?.enabled?{enabled:!0,route:authentication.apiKeys.route,keyPrefix:authentication.apiKeys.keyPrefix,maxKeysPerUser:authentication.apiKeys.maxKeysPerUser,defaultExpiresIn:authentication.apiKeys.defaultExpiresIn,allowApplicationKeys:authentication.apiKeys.allowApplicationKeys,preventApiKeyManagement:authentication.apiKeys.preventApiKeyManagement}:void 0,webauthn:authentication.webauthn},sessionsTable,oauthAccountsTable:schemaTables.oauthAccounts,oauthStateStore:(()=>{let oauthRedis=getRedisManager();if(!oauthRedis)return;let{createRedisOAuthStateStore:createRedisOAuthStateStore2}=__toCommonJS(exports_stateStore);return createRedisOAuthStateStore2(oauthRedis)})(),apiKeysTable:schemaTables.apiKeys,schemaTables,schemaRelations,tenantRegistry,getTenantRegistry:()=>tenantRegistry,databaseUrl:envResolved.databaseUrl,dbPool,admin:(()=>{let adminCfg=resolvedOptions.authentication?.admin;return{impersonate:{enabled:!0},changeUserId:{enabled:!0},createUser:adminCfg?.createUser??{enabled:!0},passwordTools:adminCfg?.passwordTools??{enabled:!1}}})(),schemaName:targetSchemaName,getEmailService,appName:resolvedOptions.appId,webauthnService:(()=>{if(!authentication.webauthn?.enabled||!db)return null;let{WebAuthnService:WebAuthnService2}=(init_WebAuthn(),__toCommonJS(exports_WebAuthn)),{createDbWebAuthnStorage:createDbWebAuthnStorage2}=(init_dbStorage(),__toCommonJS(exports_dbStorage)),rpName=authentication.webauthn.rpName||resolvedOptions.appId||"Nucleus",rpID=authentication.webauthn.rpID||"localhost",expectedOrigins=authentication.webauthn.expectedOrigins||[`http://${rpID}`,`https://${rpID}`],challengeTtlMs=authentication.webauthn.challengeTtl?parseTimeToSeconds2(authentication.webauthn.challengeTtl)*1000:300000,storage=createDbWebAuthnStorage2({db,resolveTable:resolveTableForTenant});return new WebAuthnService2({rp:{rpName,rpID,expectedOrigins},challengeTtlMs,storage,userVerification:authentication.webauthn?.userVerification,logger:logger2})})(),captchaService:(()=>{let redisManager=getRedisManager();if(!authentication.captcha?.enabled||!redisManager)return null;return new CaptchaService({redis:{get:async(key2)=>{let result=await redisManager.read(key2);return result.success?result.data:null},set:async(key2,value2,options)=>{await redisManager.create(key2,value2,options?.ex)},del:async(key2)=>{await redisManager.remove(key2)},incrementCounter:(key2,delta,ttlSeconds)=>redisManager.incrementCounter(key2,delta,ttlSeconds)},logger:logger2,config:{enabled:!0,type:authentication.captcha.type||"math",difficulty:authentication.captcha.difficulty||"medium",expiresIn:authentication.captcha.expiresIn||"5m",maxAttempts:authentication.captcha.maxAttempts||3,caseSensitive:authentication.captcha.caseSensitive??!1}})})(),tokenResponseConfig:{accessToken:{setHeadersEnabled:authentication.accessToken?.setHeadersEnabled??!0,returnJson:authentication.accessToken?.returnJson??!0},refreshToken:{setHeadersEnabled:authentication.refreshToken?.setHeadersEnabled??!0,returnJson:authentication.refreshToken?.returnJson??!0},sessionToken:{setHeadersEnabled:authentication.sessionToken?.setHeadersEnabled??!0,returnJson:authentication.sessionToken?.returnJson??!0}},helpers:{signAccessToken:(userId,roles,claims,tenant,claimScopes,sessionId)=>{let resolveMode=resolvedOptions.authorization?.jwtClaimsMode==="resolve"&&claimsCache,hasClaimScopes=!resolveMode&&!!claimScopes&&Object.keys(claimScopes).length>0,token=signJWT2({subject:userId,expiresInSeconds:parseTimeToSeconds2(authentication.accessToken?.expiresIn||"15m"),issuer:authentication.accessToken?.issuer,audience:authentication.accessToken?.audience,sessionId,customClaims:{...roles&&roles.length>0?{roles}:{},...!resolveMode&&claims&&claims.length>0?{claims}:{},...hasClaimScopes?{claimScopes}:{},...tenant?{tenant}:{}}},envResolved.accessTokenSecret||"",authentication.accessToken?.algorithm||"HS256");return warnIfAccessTokenTooLargeForCookie(token,resolveMode?"resolve":resolvedOptions.authorization?.jwtClaimsMode),token},signRefreshToken:(userId,rememberMe,sessionId)=>signJWT2({subject:userId,expiresInSeconds:longerLifetime(rememberMe?authentication.rememberMe?.expiresIn:void 0,authentication.refreshToken?.expiresIn,604800),issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience,sessionId},envResolved.refreshTokenSecret||"",authentication.refreshToken?.algorithm||"HS256"),verifyRefreshToken:(token)=>verifyJWT3(token,envResolved.refreshTokenSecret||"",{issuer:authentication.refreshToken?.issuer,audience:authentication.refreshToken?.audience}),createSession:async(params)=>{let sessionTtlSeconds=longerLifetime(params.rememberMe?authentication.rememberMe?.expiresIn:void 0,authentication.sessionToken?.expiresIn,2592000),result=await generateSession2({userId:params.userId,deviceInfo:params.deviceInfo,rememberMe:params.rememberMe,loginMethod:params.loginMethod,expiresInSeconds:sessionTtlSeconds});if(!result.success)throw logger2.error("[createSession] failed to create session",{userId:params.userId,error:result.error}),Error(`Session storage unavailable: ${result.error||"unknown error"}`);return result.session.id},destroySession:async(sessionId)=>deleteSession2({sessionId}),saveSessionToDb:async(sessionId,params,reqSchemaName)=>{let resolvedSessionsTable=resolveTableForTenant("userSessions",reqSchemaName)||resolveTableForTenant("user_sessions",reqSchemaName)||resolveTableForTenant("sessions",reqSchemaName)||sessionsTable;if(!resolvedSessionsTable||!db)return;let sessionsConfig=authentication.sessions,deviceInfo=ensureDeviceInfo(params.deviceInfo||{ipAddress:""}),resolvedUsersTableForExempt=resolveTableForTenant("users",reqSchemaName),sessionUserEmail=null;if(resolvedUsersTableForExempt)sessionUserEmail=(await db.select().from(resolvedUsersTableForExempt).where(eq70(resolvedUsersTableForExempt.id,params.userId)).limit(1))[0]?.email??null;let userIsEmailExempt=sessionUserEmail?isEmailExempt(sessionUserEmail,authentication?.emailExemptDomains):!1,deviceFingerprint=deviceInfo.deviceHint?`${deviceInfo.browserName||""}-${deviceInfo.osName||""}-${deviceInfo.deviceType||""}-${deviceInfo.deviceHint}`:`${deviceInfo.browserName||""}-${deviceInfo.osName||""}-${deviceInfo.deviceType||""}`,existingSessions=await db.select().from(resolvedSessionsTable).where(and30(eq70(resolvedSessionsTable.userId,params.userId),eq70(resolvedSessionsTable.isActive,!0))),hasValidFingerprint=deviceFingerprint&&!deviceFingerprint.includes("--unknown")&&!deviceFingerprint.includes("Bot/Crawler")&&!deviceFingerprint.includes("Headless")&&deviceFingerprint!=="--"&&deviceFingerprint!=="--unknown",allUserSessions=await db.select().from(resolvedSessionsTable).where(eq70(resolvedSessionsTable.userId,params.userId)),isNewDevice=hasValidFingerprint?!existingSessions.some((s)=>s.deviceFingerprint===deviceFingerprint):!1,wasPreviouslyApproved=hasValidFingerprint?allUserSessions.some((s)=>{let sess=s;return sess.deviceFingerprint===deviceFingerprint&&sess.approvalStatus==="approved"}):!1,hasAnyApprovedSession=existingSessions.some((s)=>s.approvalStatus==="approved"),isImpersonationLogin=params.loginMethod==="impersonation"||params.loginMethod==="impersonation_stop",isOAuthLogin=params.loginMethod?.startsWith("oauth:"),requiresApproval=!isImpersonationLogin&&!userIsEmailExempt&&sessionsConfig?.trustNewDevices===!1&&isNewDevice&&!wasPreviouslyApproved&&hasValidFingerprint&&hasAnyApprovedSession,deviceTrustCfg=sessionsConfig?.deviceTrust,dtTable=deviceTrustCfg?.enabled?resolveTableForTenant("trustedDevices",reqSchemaName)||resolveTableForTenant("trusted_devices",reqSchemaName):void 0,deviceTrustMint=null,deviceTokenToSet=null;if(deviceTrustCfg?.enabled&&dtTable){let DT=await Promise.resolve().then(() => (init_DeviceTrust(),exports_DeviceTrust)),DTStore=await Promise.resolve().then(() => (init_store3(),exports_store)),dtNow=new Date,dtRows=params.deviceToken?await DTStore.findDeviceRowsByRawToken(db,dtTable,params.deviceToken):[],knownRow=DT.selectUsableDeviceRow(dtRows,params.userId,dtNow),pendingRow=dtRows.find((r)=>(r.userId??r.user_id)===params.userId&&r.status==="pending"),isFirstEver=allUserSessions.length===0&&await DTStore.userHasNoTrustedDevices(db,dtTable,params.userId),decision=DT.decideDeviceApproval({knownDevice:!!knownRow,trustNewDevices:sessionsConfig?.trustNewDevices??!0,hasValidFingerprint:!!hasValidFingerprint,isFirstEverDevice:isFirstEver,loginMethod:params.loginMethod,approvalMethods:deviceTrustCfg.approvalMethods??["password","magic_link","sso","webauthn","oauth:*","register"],onUnidentifiable:deviceTrustCfg.onUnidentifiable??"require_approval",isImpersonation:isImpersonationLogin,isEmailExempt:userIsEmailExempt});if(knownRow)await DTStore.touchDevice(db,dtTable,knownRow.id,deviceInfo.ipAddress).catch(()=>{});if(decision.deny)return logger2.warn("[AUTH] Device-trust denied unidentifiable device",{userId:params.userId}),{requiresApproval:!1,denied:!0};let reuseSessionId=pendingRow?.originSessionId??pendingRow?.origin_session_id;if(decision.requiresApproval&&reuseSessionId)return{requiresApproval:!0,sessionId:reuseSessionId};requiresApproval=decision.requiresApproval,deviceTrustMint=decision.mintToken?decision.trustImmediately?"trusted":"pending":null}logger2.info("[AUTH] Device fingerprint analysis",{userId:params.userId,deviceFingerprint,hasValidFingerprint,isNewDevice,wasPreviouslyApproved,loginMethod:params.loginMethod,isImpersonationLogin,isOAuthLogin,existingSessionCount:existingSessions.length,hasAnyApprovedSession,requiresApproval});let approvalToken=null,approvalStatus="approved";if(requiresApproval){let existingPending=deviceTrustCfg?.enabled?void 0:allUserSessions.find((s)=>{let sess=s;return sess.deviceFingerprint===deviceFingerprint&&(sess.approvalStatus==="pending"||sess.approval_status==="pending")&&sess.approvalToken});if(existingPending){let pendingSess=existingPending,pendingRequestedAt=pendingSess.approvalRequestedAt||pendingSess.approval_requested_at;if(pendingRequestedAt?Date.now()-new Date(pendingRequestedAt).getTime()<86400000:!0)return logger2.info("[AUTH] Reusing existing pending session for same device",{userId:params.userId,deviceFingerprint,existingSessionId:pendingSess.id}),{requiresApproval:!0,sessionId:pendingSess.id}}let{randomBytes:randomBytes8}=await import("crypto");approvalToken=randomBytes8(32).toString("hex"),approvalStatus="pending",logger2.info("[AUTH] New device requires approval",{userId:params.userId,deviceFingerprint,ipAddress:deviceInfo.ipAddress})}let staleBotSessions=existingSessions.filter((s)=>{let sess=s,fp=(sess.deviceFingerprint||"").toLowerCase(),ip=sess.ipAddress||"",ua=(sess.userAgent||"").toLowerCase(),isBotFingerprint=!fp||fp==="--"||fp==="--unknown"||fp.includes("bot/crawler")||fp.includes("headless")||fp.includes("unknown-unknown"),isServerAction=ua.includes("nucleusserveraction")||ua.includes("serveraction")||ua.includes("node-fetch")||ua.includes("undici");return isBotFingerprint&&(ip==="127.0.0.1"||ip==="::1"||ip==="localhost"||!ip)||isServerAction});if(staleBotSessions.length>0){for(let botSession of staleBotSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"bot_session_cleanup"}).where(eq70(resolvedSessionsTable.id,botSession.id));logger2.info("[AUTH] Cleaned up stale bot/crawler sessions",{userId:params.userId,cleanedCount:staleBotSessions.length})}if(hasValidFingerprint&&!requiresApproval){let sameDeviceOldSessions=existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint);for(let oldSession of sameDeviceOldSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"same_device_relogin"}).where(eq70(resolvedSessionsTable.id,oldSession.id));if(sameDeviceOldSessions.length>0)logger2.info("[AUTH] Revoked old same-device sessions",{userId:params.userId,deviceFingerprint,revokedCount:sameDeviceOldSessions.length})}if(!sessionsConfig?.allowMultipleDevices&&existingSessions.length>0){if((hasValidFingerprint?existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint):[]).length===0)for(let oldSession of existingSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"new_device_login"}).where(eq70(resolvedSessionsTable.id,oldSession.id))}if(sessionsConfig?.maxActiveSessions){let{count:count3}=await import("drizzle-orm"),currentCount=(await db.select({count:count3()}).from(resolvedSessionsTable).where(and30(eq70(resolvedSessionsTable.userId,params.userId),eq70(resolvedSessionsTable.isActive,!0))))[0]?.count||0;if(currentCount>=sessionsConfig.maxActiveSessions){let{asc:asc3}=await import("drizzle-orm"),oldestSessions=await db.select().from(resolvedSessionsTable).where(and30(eq70(resolvedSessionsTable.userId,params.userId),eq70(resolvedSessionsTable.isActive,!0))).orderBy(sql15`${resolvedSessionsTable.lastActivityAt} ASC NULLS FIRST`,asc3(resolvedSessionsTable.createdAt)).limit(currentCount-sessionsConfig.maxActiveSessions+1);for(let oldSession of oldestSessions)await db.update(resolvedSessionsTable).set({isActive:!1,revokedAt:new Date,revokedReason:"max_sessions_exceeded"}).where(eq70(resolvedSessionsTable.id,oldSession.id)),await deleteSession2({sessionId:String(oldSession.id)}).catch(()=>{return})}}let trustScore=100;if(deviceInfo.isHeadless)trustScore-=50;if(deviceInfo.isBot)trustScore-=40;if(deviceInfo.isSuspicious)logger2.warn("[AUTH] Suspicious login detected",{userId:params.userId,suspiciousPatterns:deviceInfo.suspiciousPatterns,userAgent:deviceInfo.userAgent,ipAddress:deviceInfo.ipAddress});if(isNewDevice)trustScore-=25;if(!deviceInfo.ipAddress||deviceInfo.ipAddress==="unknown")trustScore-=20;if(!deviceInfo.browserName)trustScore-=15;if(!deviceInfo.osName)trustScore-=15;if(!deviceInfo.deviceType||deviceInfo.deviceType==="unknown")trustScore-=10;if(!deviceInfo.deviceName||deviceInfo.deviceName==="Unknown Device")trustScore-=5;let validFingerprint=deviceFingerprint&&!deviceFingerprint.includes("--unknown")&&deviceFingerprint!=="--",validIp=deviceInfo.ipAddress&&deviceInfo.ipAddress!=="unknown";if(validFingerprint){if(existingSessions.filter((s)=>s.deviceFingerprint===deviceFingerprint).length>0)trustScore+=20}if(validIp){if(existingSessions.filter((s)=>s.ipAddress===deviceInfo.ipAddress).length>0)trustScore+=15}trustScore=Math.max(0,Math.min(100,trustScore));let LOW_TRUST_THRESHOLD=50;if(await db.insert(resolvedSessionsTable).values({id:sessionId,userId:params.userId,tokenHash:sessionId,deviceFingerprint,deviceName:deviceInfo.deviceName,deviceType:deviceInfo.deviceType,browserName:deviceInfo.browserName,browserVersion:deviceInfo.browserVersion,osName:deviceInfo.osName,osVersion:deviceInfo.osVersion,ipAddress:deviceInfo.ipAddress,locationCountry:deviceInfo.locationCountry,locationCity:deviceInfo.locationCity,loginMethod:params.loginMethod||"password",rememberMe:params.rememberMe??!1,trustScore,lastActivityAt:new Date,createdAt:new Date,expiresAt:(()=>{let ttl=lifetimeSeconds(authentication.sessionToken?.expiresIn,2592000);return ttl===null?null:new Date(Date.now()+ttl*1000)})(),isActive:approvalStatus==="approved",approvalStatus,approvalToken,approvalRequestedAt:requiresApproval?new Date:null}),shouldNotifyDevice({emailAvailable:Boolean(getEmailService()?.isAvailable()),isImpersonationLogin:Boolean(isImpersonationLogin),notifyOnNewDevice:Boolean(sessionsConfig?.notifyOnNewDevice),isNewDevice,trustScore,lowTrustThreshold:LOW_TRUST_THRESHOLD,requiresApproval:Boolean(requiresApproval)})){let resolvedUsersTable=resolveTableForTenant("users",reqSchemaName);if(resolvedUsersTable){let user=(await db.select().from(resolvedUsersTable).where(eq70(resolvedUsersTable.id,params.userId)).limit(1))[0];if(user?.email&&!isEmailExempt(user.email,authentication?.emailExemptDomains)){let isLowTrust=trustScore<LOW_TRUST_THRESHOLD,sessionsRoute=authentication.sessions?.route||"/auth/sessions",configuredUrl=authentication.sessions?.approvalRedirectUrl||"",isLegacyFrontendUrl=!configuredUrl||configuredUrl.endsWith("/devices"),approvalBase;if(!isLegacyFrontendUrl)approvalBase=configuredUrl;else{let origin=pickTrustedOrigin(params.requestOrigin,configuredUrl,trustedAppOrigins());if(params.requestOrigin&&origin!==params.requestOrigin)logger2.warn("[AUTH] Device-approval link origin refused \u2014 not in trustedAppOrigins",{requested:params.requestOrigin,used:origin||"(none)"});approvalBase=`${origin||"http://localhost:9000"}${sessionsRoute}`}let approveUrl=approvalToken?`${approvalBase}/approve-page?token=${approvalToken}`:"",rejectUrl=approvalToken?`${approvalBase}/reject-page?token=${approvalToken}`:"",subject,emailHtml,brandName=resolvedOptions.appId||"Nucleus",loginTime=new Date().toLocaleString("en-US",{dateStyle:"medium",timeStyle:"short"}),deviceSummary=`${deviceInfo.browserName||"Unknown"} ${deviceInfo.browserVersion||""} on ${deviceInfo.osName||"Unknown"} ${deviceInfo.osVersion||""}`,emailWrapper=(content)=>`
|
|
555
555
|
<!DOCTYPE html>
|
|
556
556
|
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"></head>
|
|
557
557
|
<body style="margin:0;padding:0;background-color:#f4f4f5;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;">
|