ofauth-shared-core 0.1.0-alpha.0 → 0.1.0-alpha.1

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.
@@ -0,0 +1 @@
1
+ function ee(r){return!!(r.tenantId||r.branchId||r.attributes&&Object.keys(r.attributes).length>0)}function I(r,e){let t={basic:1,elevated:2};return t[r]>=t[e]}function ne(r){return["LOGIN_SUCCESS","LOGIN_FAILED","LOCKOUT_TRIGGERED","SESSION_REVOKED","CONTEXT_SWITCHED","STEP_UP_CHALLENGED","STEP_UP_PASSED","STEP_UP_FAILED"].includes(r)}function $(r,e){if(e)return r.find(t=>t.assignmentId===e)}function Q(r,e){var t;if(e.requiredTenantId&&r.tenantId!==e.requiredTenantId||e.requiredBranchId&&r.branchId!==e.requiredBranchId)return!1;if(e.requiredScopeAttributes){let i=(t=r.attributes)!=null?t:{};for(let[n,s]of Object.entries(e.requiredScopeAttributes))if(i[n]!==s)return!1}return!0}async function O(r,e){var a,d,u;let t=await r.sessionService.getActiveSession(e.sessionId);if(!t)return null;let i=await r.contextService.listAssignments(e.identityId),n=await r.contextService.getActiveContext(e.sessionId);!n&&i[0]&&(n=(await r.contextService.switchContext({sessionId:e.sessionId,targetAssignmentId:i[0].assignmentId,...e.assignmentFallbackReason?{reasonCode:e.assignmentFallbackReason}:{}})).activeContext);let s=$(i,n==null?void 0:n.assignmentId);return{sessionId:e.sessionId,identityId:e.identityId,principal:e.principal,assignments:i,activeContextAssignmentId:n==null?void 0:n.assignmentId,activeAssignment:s,scopeRef:(u=(d=(a=n==null?void 0:n.scopeRef)!=null?a:s==null?void 0:s.scopeRef)!=null?d:t.activeScopeRef)!=null?u:{},roleRef:s==null?void 0:s.roleRef,assuranceLevel:t.assuranceLevel}}async function oe(r,e){let t=await r.identityService.login(e),i=await O(r,{sessionId:t.sessionId,identityId:t.identity.identityId,principal:t.identity.principal,assignmentFallbackReason:"AUTO_CONTEXT_AFTER_LOGIN"});if(!i)throw new Error("session is not active after login");return i}async function ae(r,e){return O(r,e)}async function de(r,e){await r.contextService.switchContext({sessionId:e.sessionId,targetAssignmentId:e.targetAssignmentId,...e.reasonCode?{reasonCode:e.reasonCode}:{}});let t=await O(r,e);if(!t)throw new Error("session is not active while switching context");return t}function ce(r,e={}){var i,n;if(!r)return{allowed:!1,reasonCode:"NO_SESSION"};let t=(i=e.minimumAssuranceLevel)!=null?i:"basic";return I(r.assuranceLevel,t)?(n=e.requiredRoleRefs)!=null&&n.length&&!(!!r.roleRef&&e.requiredRoleRefs.includes(r.roleRef))?{allowed:!1,reasonCode:"ROLE_FORBIDDEN"}:Q(r.scopeRef,e)?{allowed:!0}:{allowed:!1,reasonCode:"SCOPE_FORBIDDEN"}:{allowed:!1,reasonCode:"ASSURANCE_TOO_LOW"}}function p(r){throw{code:"AUTH_NOT_IMPLEMENTED",message:r,retryable:!1}}function pe(){return{identityService:{async verifyCredential(){return p("identityService.verifyCredential not implemented yet")},async login(){return p("identityService.login not implemented yet")},async logout(){return p("identityService.logout not implemented yet")}},sessionService:{async createSession(){return p("sessionService.createSession not implemented yet")},async refreshSession(){return p("sessionService.refreshSession not implemented yet")},async revokeSession(){return p("sessionService.revokeSession not implemented yet")},async getActiveSession(){return p("sessionService.getActiveSession not implemented yet")}},contextService:{async listAssignments(){return p("contextService.listAssignments not implemented yet")},async getActiveContext(){return p("contextService.getActiveContext not implemented yet")},async switchContext(){return p("contextService.switchContext not implemented yet")}},authPolicyService:{async getPolicySnapshot(){return p("authPolicyService.getPolicySnapshot not implemented yet")},async getStepUpRequirement(){return p("authPolicyService.getStepUpRequirement not implemented yet")},async evaluateStepUp(){return p("authPolicyService.evaluateStepUp not implemented yet")},async enforceStepUp(){return p("authPolicyService.enforceStepUp not implemented yet")},async markStepUpPassed(){return p("authPolicyService.markStepUpPassed not implemented yet")}},authAuditService:{async appendEvent(){return p("authAuditService.appendEvent not implemented yet")},async queryEvents(){return p("authAuditService.queryEvents not implemented yet")},async listPendingReplay(){return p("authAuditService.listPendingReplay not implemented yet")},async markReplayed(){return p("authAuditService.markReplayed not implemented yet")}}}}var o={identities:"ofauth_identities",assignments:"ofauth_assignments",sessions:"ofauth_sessions",policyProfiles:"ofauth_policy_profiles",policyStepups:"ofauth_policy_stepups",auditEvents:"ofauth_audit_events"},Y=[{name:o.identities,columns:[{name:"id",type:"string"},{name:"principal",type:"string",isIndexed:!0},{name:"secretHash",type:"string"},{name:"verifyMethod",type:"string",enum:["pin","password","custom"]},{name:"status",type:"string",enum:["active","disabled","locked"],isIndexed:!0},{name:"failedAttempts",type:"number"},{name:"lockoutUntil",type:"string",isOptional:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.assignments,columns:[{name:"id",type:"string"},{name:"identityId",type:"string",isIndexed:!0},{name:"roleRef",type:"string",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"scopeAttributes",type:"json",isOptional:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.sessions,columns:[{name:"id",type:"string"},{name:"identityId",type:"string",isIndexed:!0},{name:"activeAssignmentId",type:"string",isOptional:!0,isIndexed:!0},{name:"assuranceLevel",type:"string",enum:["basic","elevated"],isIndexed:!0},{name:"issuedAt",type:"string"},{name:"expiresAt",type:"string",isIndexed:!0},{name:"revokedAt",type:"string",isOptional:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.policyProfiles,columns:[{name:"id",type:"string"},{name:"profileId",type:"string",isIndexed:!0},{name:"defaultAssuranceLevel",type:"string",enum:["basic","elevated"]},{name:"lockoutPolicyRef",type:"string"},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.policyStepups,columns:[{name:"id",type:"string"},{name:"actionRef",type:"string",isIndexed:!0},{name:"requiredAssuranceLevel",type:"string",enum:["basic","elevated"]},{name:"reauthWindowSeconds",type:"number",isOptional:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.auditEvents,columns:[{name:"id",type:"string"},{name:"eventType",type:"string",isIndexed:!0},{name:"identityId",type:"string",isOptional:!0,isIndexed:!0},{name:"sessionId",type:"string",isOptional:!0,isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"scopeAttributes",type:"json",isOptional:!0},{name:"result",type:"string",enum:["success","failed"],isIndexed:!0},{name:"reasonCode",type:"string",isOptional:!0},{name:"timestamp",type:"string",isIndexed:!0},{name:"syncStatus",type:"string",enum:["pending","replayed"],isIndexed:!0},{name:"replayedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]}],z={version:2,tables:Y};function k(){return z.tables}var U=5,N=900,T=480*60;function c(){return new Date().toISOString()}function h(r,e){return new Date(new Date(r).getTime()+e*1e3).toISOString()}function S(r){return new Date(r).getTime()<=Date.now()}function f(r){let e=0;return()=>(e+=1,`${r}-${Date.now()}-${e}`)}function F(r){return{identityId:r.id,principal:r.principal,status:r.status}}function H(r){return{assignmentId:r.id,identityId:r.identityId,roleRef:r.roleRef,scopeRef:{...r.tenantId?{tenantId:r.tenantId}:{},...r.branchId?{branchId:r.branchId}:{},...r.scopeAttributes?{attributes:r.scopeAttributes}:{}}}}function v(r,e){return{sessionId:r.id,identityId:r.identityId,activeScopeRef:e?{...e.tenantId?{tenantId:e.tenantId}:{},...e.branchId?{branchId:e.branchId}:{},...e.scopeAttributes?{attributes:e.scopeAttributes}:{}}:void 0,assuranceLevel:r.assuranceLevel,issuedAt:r.issuedAt,expiresAt:r.expiresAt}}async function q(r,e,t){return r?r.verifyPin(e,t):e===t}async function M(r,e){var t,i,n,s,a,d;r.emitActivity&&await r.emitActivity({activityId:e.eventId,activityType:`ofauth.${e.eventType.toLowerCase()}`,occurredAt:e.timestamp,scopeRef:{domain:"ofauth",...(t=e.scopeRef)!=null&&t.tenantId?{tenantId:e.scopeRef.tenantId}:{},...(i=e.scopeRef)!=null&&i.branchId?{branchId:e.scopeRef.branchId}:{}},actor:e.identityId?{userId:e.identityId}:void 0,payload:{eventType:e.eventType,result:e.result,reasonCode:(n=e.reasonCode)!=null?n:null,sessionId:(s=e.sessionId)!=null?s:null,scopeAttributes:(d=(a=e.scopeRef)==null?void 0:a.attributes)!=null?d:null}})}async function y(r,e){if(!e)return null;let t=await r.get(o.assignments,e);return!t||t.deleted?null:t}function B(){return[{profileId:"cashier_fast",defaultAssuranceLevel:"basic",lockoutPolicyRef:"default"},{profileId:"supervisor_strict",defaultAssuranceLevel:"elevated",lockoutPolicyRef:"strict"},{profileId:"member_self_service",defaultAssuranceLevel:"basic",lockoutPolicyRef:"member"}]}var R=class{constructor(e,t){this.db=e;this.options=t;this.newId=f("auth-audit")}async appendEvent(e){var i,n,s,a,d,u,l,A,g,L,_;let t={id:e.eventId||this.newId(),eventType:e.eventType,identityId:(i=e.identityId)!=null?i:null,sessionId:(n=e.sessionId)!=null?n:null,tenantId:(a=(s=e.scopeRef)==null?void 0:s.tenantId)!=null?a:null,branchId:(u=(d=e.scopeRef)==null?void 0:d.branchId)!=null?u:null,scopeAttributes:(A=(l=e.scopeRef)==null?void 0:l.attributes)!=null?A:null,result:e.result,reasonCode:(g=e.reasonCode)!=null?g:null,timestamp:e.timestamp,syncStatus:(L=e.syncStatus)!=null?L:"pending",replayedAt:(_=e.replayedAt)!=null?_:null,version:1,lastModified:c(),deleted:!1};await this.db.create(o.auditEvents,t),await M(this.options,e)}async queryEvents(e){return(await this.db.query(o.auditEvents,{filters:{deleted:!1},sort:[{field:"timestamp",direction:"desc"}]})).filter(i=>e.identityId?i.identityId===e.identityId:!0).filter(i=>e.sessionId?i.sessionId===e.sessionId:!0).filter(i=>{var n;return(n=e.eventTypes)!=null&&n.length?e.eventTypes.includes(i.eventType):!0}).filter(i=>e.fromTimestamp?i.timestamp>=e.fromTimestamp:!0).filter(i=>e.toTimestamp?i.timestamp<=e.toTimestamp:!0).map(i=>{var n,s,a,d,u;return{eventId:i.id,eventType:i.eventType,identityId:(n=i.identityId)!=null?n:void 0,sessionId:(s=i.sessionId)!=null?s:void 0,scopeRef:i.tenantId||i.branchId||i.scopeAttributes?{...i.tenantId?{tenantId:i.tenantId}:{},...i.branchId?{branchId:i.branchId}:{},...i.scopeAttributes?{attributes:i.scopeAttributes}:{}}:void 0,result:i.result,reasonCode:(a=i.reasonCode)!=null?a:void 0,timestamp:i.timestamp,syncStatus:(d=i.syncStatus)!=null?d:"pending",replayedAt:(u=i.replayedAt)!=null?u:void 0}})}async listPendingReplay(e={}){var i;let t=await this.db.query(o.auditEvents,{filters:{deleted:!1},sort:[{field:"timestamp",direction:"asc"}]});return t.filter(n=>n.syncStatus!=="replayed").slice(0,(i=e.limit)!=null?i:t.length).map(n=>{var s,a,d,u,l;return{eventId:n.id,eventType:n.eventType,identityId:(s=n.identityId)!=null?s:void 0,sessionId:(a=n.sessionId)!=null?a:void 0,scopeRef:n.tenantId||n.branchId||n.scopeAttributes?{...n.tenantId?{tenantId:n.tenantId}:{},...n.branchId?{branchId:n.branchId}:{},...n.scopeAttributes?{attributes:n.scopeAttributes}:{}}:void 0,result:n.result,reasonCode:(d=n.reasonCode)!=null?d:void 0,timestamp:n.timestamp,syncStatus:(u=n.syncStatus)!=null?u:"pending",replayedAt:(l=n.replayedAt)!=null?l:void 0}})}async markReplayed(e,t=c()){let i=0;for(let n of e){let s=await this.db.get(o.auditEvents,n);!s||s.deleted||s.syncStatus==="replayed"||(await this.db.update(o.auditEvents,n,{syncStatus:"replayed",replayedAt:t,version:s.version+1,lastModified:c()}),i+=1)}return i}};var b=class extends Error{constructor(t,i,n=!1){super(i);this.code=t;this.retryable=n;this.name="OfauthDomainError"}};function m(r,e){return new b(r,e,!1)}function he(r){return new b("AUTH_NOT_IMPLEMENTED",r,!1)}var w=class{constructor(e,t){this.db=e;this.authAuditService=t;this.newEventId=f("auth-event")}async getActiveSessionOrThrow(e){let t=await this.db.get(o.sessions,e);if(!t||t.deleted||t.revokedAt||S(t.expiresAt))throw m("AUTH_SESSION_NOT_FOUND","Session not found");return t}async getPolicySnapshot(){let e=await this.db.query(o.policyProfiles,{filters:{deleted:!1},sort:[{field:"lastModified",direction:"desc"}]}),t=await this.db.query(o.policyStepups,{filters:{deleted:!1},sort:[{field:"lastModified",direction:"desc"}]});return{profiles:e.length>0?e.map(i=>({profileId:i.profileId,defaultAssuranceLevel:i.defaultAssuranceLevel,lockoutPolicyRef:i.lockoutPolicyRef})):B(),stepUpRequirements:t.map(i=>{var n;return{actionRef:i.actionRef,requiredAssuranceLevel:i.requiredAssuranceLevel,reauthWindowSeconds:(n=i.reauthWindowSeconds)!=null?n:void 0}}),version:"1",updatedAt:c()}}async getStepUpRequirement(e){var i;let t=await this.db.query(o.policyStepups,{filters:{actionRef:e,deleted:!1},limit:1});return t[0]?{actionRef:t[0].actionRef,requiredAssuranceLevel:t[0].requiredAssuranceLevel,reauthWindowSeconds:(i=t[0].reauthWindowSeconds)!=null?i:void 0}:null}async evaluateStepUp(e,t){var d;let i=await this.getActiveSessionOrThrow(e),n=await this.getStepUpRequirement(t),s=(d=n==null?void 0:n.requiredAssuranceLevel)!=null?d:"basic",a=!I(i.assuranceLevel,s);return{actionRef:t,requiredAssuranceLevel:s,currentAssuranceLevel:i.assuranceLevel,requiresStepUp:a,reauthWindowSeconds:n==null?void 0:n.reauthWindowSeconds}}async enforceStepUp(e,t){let i=await this.getActiveSessionOrThrow(e),n=await this.evaluateStepUp(e,t);if(n.requiresStepUp)throw await this.authAuditService.appendEvent({eventId:this.newEventId(),eventType:"STEP_UP_CHALLENGED",identityId:i.identityId,sessionId:e,result:"failed",reasonCode:"AUTH_STEP_UP_REQUIRED",timestamp:c()}),m("AUTH_STEP_UP_REQUIRED",`Step-up required for action '${t}' (needs ${n.requiredAssuranceLevel})`)}async markStepUpPassed(e,t){var u;let i=await this.getActiveSessionOrThrow(e),n=await this.getStepUpRequirement(t),s=(u=n==null?void 0:n.requiredAssuranceLevel)!=null?u:"elevated";await this.db.update(o.sessions,e,{assuranceLevel:s,version:i.version+1,lastModified:c()}),await this.authAuditService.appendEvent({eventId:this.newEventId(),eventType:"STEP_UP_PASSED",identityId:i.identityId,sessionId:e,result:"success",reasonCode:t,timestamp:c()});let a=await this.db.get(o.sessions,e),d=a?await y(this.db,a.activeAssignmentId):null;if(!a)throw m("AUTH_SESSION_NOT_FOUND","Session not found");return v(a,d!=null?d:void 0)}};var C=class{constructor(e,t){this.db=e;this.authAuditService=t;this.newEventId=f("auth-event")}async listAssignments(e){return(await this.db.query(o.assignments,{filters:{identityId:e,deleted:!1},sort:[{field:"lastModified",direction:"desc"}]})).map(H)}async getActiveContext(e){let t=await this.db.get(o.sessions,e);if(!t||t.deleted||t.revokedAt||!t.activeAssignmentId)return null;let i=await y(this.db,t.activeAssignmentId);return i?{sessionId:e,assignmentId:i.id,scopeRef:{...i.tenantId?{tenantId:i.tenantId}:{},...i.branchId?{branchId:i.branchId}:{},...i.scopeAttributes?{attributes:i.scopeAttributes}:{}}}:null}async switchContext(e){let t=await this.db.get(o.sessions,e.sessionId);if(!t||t.deleted||t.revokedAt)throw m("AUTH_SESSION_NOT_FOUND","Session not found");let i=await y(this.db,e.targetAssignmentId);if(!i||i.identityId!==t.identityId)throw m("AUTH_CONTEXT_FORBIDDEN","Requested context is not assigned to this identity");let n=await this.db.update(o.sessions,e.sessionId,{activeAssignmentId:i.id,version:t.version+1,lastModified:c()});return await this.authAuditService.appendEvent({eventId:this.newEventId(),eventType:"CONTEXT_SWITCHED",identityId:t.identityId,sessionId:e.sessionId,scopeRef:{...i.tenantId?{tenantId:i.tenantId}:{},...i.branchId?{branchId:i.branchId}:{},...i.scopeAttributes?{attributes:i.scopeAttributes}:{}},result:"success",reasonCode:e.reasonCode,timestamp:n.lastModified}),{activeContext:{sessionId:e.sessionId,assignmentId:i.id,scopeRef:{...i.tenantId?{tenantId:i.tenantId}:{},...i.branchId?{branchId:i.branchId}:{},...i.scopeAttributes?{attributes:i.scopeAttributes}:{}}},requiresStepUp:!1,reasonCode:e.reasonCode}}};var x=class{constructor(e,t,i,n,s){this.db=e;this.options=t;this.sessionService=i;this.contextService=n;this.authAuditService=s;this.newEventId=f("auth-event")}async findIdentityByPrincipal(e){var i;return(i=(await this.db.query(o.identities,{filters:{principal:e,deleted:!1},limit:1}))[0])!=null?i:null}async persistFailedAttempt(e){let t=e.failedAttempts+1,i=t>=U,n=i?h(c(),N):null,s=i?"locked":e.status;return this.db.update(o.identities,e.id,{failedAttempts:t,lockoutUntil:n,status:s,version:e.version+1,lastModified:c()})}async clearFailedAttempt(e){e.failedAttempts===0&&!e.lockoutUntil&&e.status==="active"||await this.db.update(o.identities,e.id,{failedAttempts:0,lockoutUntil:null,status:"active",version:e.version+1,lastModified:c()})}async emitAudit(e){await this.authAuditService.appendEvent(e)}async verifyCredential(e){let t=await this.findIdentityByPrincipal(e.principal);if(!t)return await this.emitAudit({eventId:this.newEventId(),eventType:"LOGIN_FAILED",result:"failed",reasonCode:"INVALID_CREDENTIAL",timestamp:c()}),{ok:!1,reasonCode:"INVALID_CREDENTIAL",retryable:!0};if(t.status==="disabled")return await this.emitAudit({eventId:this.newEventId(),eventType:"LOGIN_FAILED",identityId:t.id,result:"failed",reasonCode:"IDENTITY_DISABLED",timestamp:c()}),{ok:!1,reasonCode:"IDENTITY_DISABLED",retryable:!1};if(t.lockoutUntil&&!S(t.lockoutUntil))return await this.emitAudit({eventId:this.newEventId(),eventType:"LOCKOUT_TRIGGERED",identityId:t.id,result:"failed",reasonCode:"IDENTITY_LOCKED",timestamp:c()}),{ok:!1,reasonCode:"IDENTITY_LOCKED",retryable:!1};if(!await q(this.options.platformAdapter,e.secret,t.secretHash)){let a=(await this.persistFailedAttempt(t)).status==="locked"?"IDENTITY_LOCKED":"INVALID_CREDENTIAL";return await this.emitAudit({eventId:this.newEventId(),eventType:a==="IDENTITY_LOCKED"?"LOCKOUT_TRIGGERED":"LOGIN_FAILED",identityId:t.id,result:"failed",reasonCode:a,timestamp:c()}),{ok:!1,reasonCode:a,retryable:a==="INVALID_CREDENTIAL"}}await this.clearFailedAttempt(t);let n=await this.contextService.listAssignments(t.id);return await this.emitAudit({eventId:this.newEventId(),eventType:"LOGIN_SUCCESS",identityId:t.id,scopeRef:e.scopeRef,result:"success",timestamp:c()}),{ok:!0,identity:F(t),assignments:n}}async login(e){let t=await this.verifyCredential({principal:e.principal,secret:e.secret,verifyMethod:e.verifyMethod});if(!t.ok)throw m("AUTH_INVALID_CREDENTIAL",`Authentication failed: ${t.reasonCode}`);let i=[...t.assignments].sort((s,a)=>s.assignmentId.localeCompare(a.assignmentId))[0],n=await this.sessionService.createSession({identityId:t.identity.identityId,assignmentId:i==null?void 0:i.assignmentId,assuranceLevel:"basic"});return{identity:t.identity,sessionId:n.sessionId}}async logout(e){await this.sessionService.revokeSession({sessionId:e,reasonCode:"LOGOUT"}),await this.emitAudit({eventId:this.newEventId(),eventType:"SESSION_REVOKED",sessionId:e,result:"success",reasonCode:"LOGOUT",timestamp:c()})}};var E=class{constructor(e,t){this.db=e;this.options=t;this.newId=f("auth-session")}async createSession(e){var a,d,u,l;let t=c(),i=h(t,(a=e.ttlSeconds)!=null?a:T),n=await this.db.create(o.sessions,{id:this.newId(),identityId:e.identityId,activeAssignmentId:(d=e.assignmentId)!=null?d:null,assuranceLevel:(u=e.assuranceLevel)!=null?u:"basic",issuedAt:t,expiresAt:i,revokedAt:null,version:1,lastModified:t,deleted:!1}),s=await y(this.db,n.activeAssignmentId);return(l=this.options.logger)==null||l.logInfo("[ofauth] session created",{sessionId:n.id,identityId:n.identityId}),v(n,s)}async refreshSession(e){var s;let t=await this.db.get(o.sessions,e.sessionId);if(!t||t.deleted||t.revokedAt)throw m("AUTH_SESSION_NOT_FOUND","Session not found");let i=await this.db.update(o.sessions,e.sessionId,{expiresAt:h(c(),(s=e.ttlSeconds)!=null?s:T),version:t.version+1,lastModified:c()}),n=await y(this.db,i.activeAssignmentId);return v(i,n)}async revokeSession(e){var i,n;let t=await this.db.get(o.sessions,e.sessionId);!t||t.deleted||t.revokedAt||(await this.db.update(o.sessions,e.sessionId,{revokedAt:c(),version:t.version+1,lastModified:c()}),(n=this.options.logger)==null||n.logInfo("[ofauth] session revoked",{sessionId:e.sessionId,reasonCode:(i=e.reasonCode)!=null?i:null}))}async getActiveSession(e){let t=await this.db.get(o.sessions,e);if(!t||t.deleted||t.revokedAt||S(t.expiresAt))return null;let i=await y(this.db,t.activeAssignmentId);return v(t,i)}};async function G(r,e={}){let t=new R(r,e),i=new E(r,e),n=new C(r,t),s=new w(r,t);return{identityService:new x(r,e,i,n,t),sessionService:i,contextService:n,authPolicyService:s,authAuditService:t}}var We="phase1-contract-only";import{CoreRuntime as j}from"ofcore";import{InMemoryDbAdapter as K}from"ofcore";import{asReadonlyStore as J,createStore as Z}from"ofcore";var V=[{toVersion:1,up:async r=>{let e=k();for(let t of e)try{await r.addTable(t)}catch{}}},{toVersion:2,up:async r=>{try{await r.addColumn(o.auditEvents,{name:"syncStatus",type:"string",enum:["pending","replayed"],isIndexed:!0})}catch{}try{await r.addColumn(o.auditEvents,{name:"replayedAt",type:"string",isOptional:!0,isIndexed:!0})}catch{}}}];var X={logInfo(){},logWarn(){},logError(){}};async function W(r,e=X){e.logInfo("[ofauth] starting database migration process");let t=[...V].sort((s,a)=>s.toVersion-a.toVersion),i=t.length>0?t[t.length-1].toVersion:0,n=await r.getSchemaVersion();if((n==null||n<0)&&(n=0),n>=i){e.logInfo(`[ofauth] database already up-to-date at v${n}`);return}for(let s of t)s.toVersion>n&&(e.logInfo(`[ofauth] applying migration v${s.toVersion}`),await s.up(r),await r.setSchemaVersion(s.toVersion),n=s.toVersion);e.logInfo(`[ofauth] migration completed at v${n}`)}var P=class{constructor(e,t){this.runtime=e;this.runtimeStateStore=t;this.runtimeStore=J(this.runtimeStateStore)}static builder(){return new D}get registry(){return this.runtime.registry}async start(e={}){this.runtimeStateStore.setState({phase:"starting",started:!1,lastError:null,lastTransitionAt:new Date().toISOString()});try{await this.runtime.start(e),this.domainServices=this.runtime.domainServices,this.runtimeStateStore.setState(t=>({...t,phase:"started",started:!0,startCount:t.startCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(t){throw this.runtimeStateStore.setState({phase:"error",started:!1,lastError:t instanceof Error?t.message:String(t),lastTransitionAt:new Date().toISOString()}),t}}async init(e={}){this.runtimeStateStore.setState({phase:"starting",started:!1,lastError:null,lastTransitionAt:new Date().toISOString()});try{await this.runtime.init(e),this.domainServices=this.runtime.domainServices,this.runtimeStateStore.setState(t=>({...t,phase:"started",started:!0,startCount:t.startCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(t){throw this.runtimeStateStore.setState({phase:"error",started:!1,lastError:t instanceof Error?t.message:String(t),lastTransitionAt:new Date().toISOString()}),t}}async stop(){this.runtimeStateStore.setState({phase:"stopping",started:this.runtime.isStarted(),lastError:null,lastTransitionAt:new Date().toISOString()});try{await this.runtime.stop(),this.runtimeStateStore.setState(e=>({...e,phase:"stopped",started:!1,stopCount:e.stopCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(e){throw this.runtimeStateStore.setState({phase:"error",started:this.runtime.isStarted(),lastError:e instanceof Error?e.message:String(e),lastTransitionAt:new Date().toISOString()}),e}}isStarted(){return this.runtime.isStarted()}},D=class{constructor(){this.runtimeBuilder=j.builder();this.domainServiceOverrides={};this.runtimeHooks={};this.runtimeBuilder.withDbAdapter(()=>new K)}withPlatformAdapter(e){return this.runtimeBuilder.withPlatformAdapter(e),this}withDbAdapter(e){return this.runtimeBuilder.withDbAdapter(e),this}withHttpAdapter(e){return this.runtimeBuilder.withHttpAdapter(e),this}withSocketAdapter(e){return this.runtimeBuilder.withSocketAdapter(e),this}withLoggerAdapter(e){return this.runtimeBuilder.withLoggerAdapter(e),this}withActivitySink(e){return this.runtimeBuilder.withActivitySink(e),this}withExtension(e,t){return this.runtimeBuilder.withExtension(e,t),this}withDomainServicesFactory(e){return this.domainServicesFactory=e,this}overrideDomainServices(e){return this.domainServiceOverrides={...this.domainServiceOverrides,...e},this}withRuntimeHooks(e){return this.runtimeHooks={...this.runtimeHooks,...e},this}withMigrationRunner(e){return this.withRuntimeHooks({runMigrations:e})}withSeedRunner(e){return this.withRuntimeHooks({runSeed:e})}build(){var n;let e=Z({phase:"idle",started:!1,startCount:0,stopCount:0,lastError:null,lastTransitionAt:new Date().toISOString()}),t=async s=>{var d,u;let a=(d=s.registry)==null?void 0:d.dbAdapter;a&&await W(a,(u=s.registry)==null?void 0:u.loggerAdapter)};this.runtimeBuilder.withHooks({...this.runtimeHooks,runMigrations:(n=this.runtimeHooks.runMigrations)!=null?n:t,createDomainServices:async s=>{var d,u,l,A;return{...this.domainServicesFactory?await this.domainServicesFactory():await G((u=(d=s.registry)==null?void 0:d.dbAdapter)!=null?u:new K,{logger:(l=s.registry)==null?void 0:l.loggerAdapter,platformAdapter:(A=s.registry)==null?void 0:A.platformAdapter,emitActivity:async g=>{await s.emitActivity(g)}}),...this.domainServiceOverrides}}});let i=this.runtimeBuilder.build();return new P(i,e)}};export{We as OFAUTH_CONTRACT_STAGE,o as OFAUTH_TABLES,P as OfauthCore,D as OfauthCoreBuilder,b as OfauthDomainError,W as applyPendingMigrations,pe as createContractOnlyOfauthServices,G as createDbAdapterOfauthServices,ce as evaluateProtectedRouteGate,k as getOfauthTableSchemas,ee as hasAnyScopeDimension,he as invalidState,I as isAssuranceLevelAtLeast,ne as isAuthAuditEventType,oe as loginWithResolvedContext,V as migrations,z as ofauthSchema,ae as refreshResolvedContext,de as switchContextWithResolvedState,m as unauthorized};
package/dist/index.js CHANGED
@@ -1,36 +1 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./contracts/ContextContract"), exports);
18
- __exportStar(require("./contracts/IdentityContract"), exports);
19
- __exportStar(require("./contracts/SessionContract"), exports);
20
- __exportStar(require("./contracts/AuthPolicyContract"), exports);
21
- __exportStar(require("./contracts/AuthAuditContract"), exports);
22
- __exportStar(require("./contracts/AuthErrorContract"), exports);
23
- __exportStar(require("./services/IdentityService"), exports);
24
- __exportStar(require("./services/SessionService"), exports);
25
- __exportStar(require("./services/ContextService"), exports);
26
- __exportStar(require("./services/AuthHostComposition"), exports);
27
- __exportStar(require("./services/AuthPolicyService"), exports);
28
- __exportStar(require("./services/AuthAuditService"), exports);
29
- __exportStar(require("./services/createContractOnlyOfauthServices"), exports);
30
- __exportStar(require("./services/createDbAdapterOfauthServices"), exports);
31
- __exportStar(require("./services/errors"), exports);
32
- __exportStar(require("./runtime/ContractStage"), exports);
33
- __exportStar(require("./OfauthCore"), exports);
34
- __exportStar(require("./data/schemas"), exports);
35
- __exportStar(require("./data/migrations"), exports);
36
- __exportStar(require("./data/applyPendingMigrations"), exports);
1
+ "use strict";var D=Object.defineProperty;var X=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var J=Object.prototype.hasOwnProperty;var Z=(r,e)=>{for(var t in e)D(r,t,{get:e[t],enumerable:!0})},ee=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of j(e))!J.call(r,n)&&n!==t&&D(r,n,{get:()=>e[n],enumerable:!(i=X(e,n))||i.enumerable});return r};var te=r=>ee(D({},"__esModule",{value:!0}),r);var ye={};Z(ye,{OFAUTH_CONTRACT_STAGE:()=>me,OFAUTH_TABLES:()=>o,OfauthCore:()=>O,OfauthCoreBuilder:()=>T,OfauthDomainError:()=>I,applyPendingMigrations:()=>F,createContractOnlyOfauthServices:()=>ue,createDbAdapterOfauthServices:()=>U,evaluateProtectedRouteGate:()=>ce,getOfauthTableSchemas:()=>_,hasAnyScopeDimension:()=>ie,invalidState:()=>le,isAssuranceLevelAtLeast:()=>h,isAuthAuditEventType:()=>ne,loginWithResolvedContext:()=>oe,migrations:()=>N,ofauthSchema:()=>B,refreshResolvedContext:()=>ae,switchContextWithResolvedState:()=>de,unauthorized:()=>m});module.exports=te(ye);function ie(r){return!!(r.tenantId||r.branchId||r.attributes&&Object.keys(r.attributes).length>0)}function h(r,e){let t={basic:1,elevated:2};return t[r]>=t[e]}function ne(r){return["LOGIN_SUCCESS","LOGIN_FAILED","LOCKOUT_TRIGGERED","SESSION_REVOKED","CONTEXT_SWITCHED","STEP_UP_CHALLENGED","STEP_UP_PASSED","STEP_UP_FAILED"].includes(r)}function re(r,e){if(e)return r.find(t=>t.assignmentId===e)}function se(r,e){var t;if(e.requiredTenantId&&r.tenantId!==e.requiredTenantId||e.requiredBranchId&&r.branchId!==e.requiredBranchId)return!1;if(e.requiredScopeAttributes){let i=(t=r.attributes)!=null?t:{};for(let[n,s]of Object.entries(e.requiredScopeAttributes))if(i[n]!==s)return!1}return!0}async function L(r,e){var a,d,u;let t=await r.sessionService.getActiveSession(e.sessionId);if(!t)return null;let i=await r.contextService.listAssignments(e.identityId),n=await r.contextService.getActiveContext(e.sessionId);!n&&i[0]&&(n=(await r.contextService.switchContext({sessionId:e.sessionId,targetAssignmentId:i[0].assignmentId,...e.assignmentFallbackReason?{reasonCode:e.assignmentFallbackReason}:{}})).activeContext);let s=re(i,n==null?void 0:n.assignmentId);return{sessionId:e.sessionId,identityId:e.identityId,principal:e.principal,assignments:i,activeContextAssignmentId:n==null?void 0:n.assignmentId,activeAssignment:s,scopeRef:(u=(d=(a=n==null?void 0:n.scopeRef)!=null?a:s==null?void 0:s.scopeRef)!=null?d:t.activeScopeRef)!=null?u:{},roleRef:s==null?void 0:s.roleRef,assuranceLevel:t.assuranceLevel}}async function oe(r,e){let t=await r.identityService.login(e),i=await L(r,{sessionId:t.sessionId,identityId:t.identity.identityId,principal:t.identity.principal,assignmentFallbackReason:"AUTO_CONTEXT_AFTER_LOGIN"});if(!i)throw new Error("session is not active after login");return i}async function ae(r,e){return L(r,e)}async function de(r,e){await r.contextService.switchContext({sessionId:e.sessionId,targetAssignmentId:e.targetAssignmentId,...e.reasonCode?{reasonCode:e.reasonCode}:{}});let t=await L(r,e);if(!t)throw new Error("session is not active while switching context");return t}function ce(r,e={}){var i,n;if(!r)return{allowed:!1,reasonCode:"NO_SESSION"};let t=(i=e.minimumAssuranceLevel)!=null?i:"basic";return h(r.assuranceLevel,t)?(n=e.requiredRoleRefs)!=null&&n.length&&!(!!r.roleRef&&e.requiredRoleRefs.includes(r.roleRef))?{allowed:!1,reasonCode:"ROLE_FORBIDDEN"}:se(r.scopeRef,e)?{allowed:!0}:{allowed:!1,reasonCode:"SCOPE_FORBIDDEN"}:{allowed:!1,reasonCode:"ASSURANCE_TOO_LOW"}}function p(r){throw{code:"AUTH_NOT_IMPLEMENTED",message:r,retryable:!1}}function ue(){return{identityService:{async verifyCredential(){return p("identityService.verifyCredential not implemented yet")},async login(){return p("identityService.login not implemented yet")},async logout(){return p("identityService.logout not implemented yet")}},sessionService:{async createSession(){return p("sessionService.createSession not implemented yet")},async refreshSession(){return p("sessionService.refreshSession not implemented yet")},async revokeSession(){return p("sessionService.revokeSession not implemented yet")},async getActiveSession(){return p("sessionService.getActiveSession not implemented yet")}},contextService:{async listAssignments(){return p("contextService.listAssignments not implemented yet")},async getActiveContext(){return p("contextService.getActiveContext not implemented yet")},async switchContext(){return p("contextService.switchContext not implemented yet")}},authPolicyService:{async getPolicySnapshot(){return p("authPolicyService.getPolicySnapshot not implemented yet")},async getStepUpRequirement(){return p("authPolicyService.getStepUpRequirement not implemented yet")},async evaluateStepUp(){return p("authPolicyService.evaluateStepUp not implemented yet")},async enforceStepUp(){return p("authPolicyService.enforceStepUp not implemented yet")},async markStepUpPassed(){return p("authPolicyService.markStepUpPassed not implemented yet")}},authAuditService:{async appendEvent(){return p("authAuditService.appendEvent not implemented yet")},async queryEvents(){return p("authAuditService.queryEvents not implemented yet")},async listPendingReplay(){return p("authAuditService.listPendingReplay not implemented yet")},async markReplayed(){return p("authAuditService.markReplayed not implemented yet")}}}}var o={identities:"ofauth_identities",assignments:"ofauth_assignments",sessions:"ofauth_sessions",policyProfiles:"ofauth_policy_profiles",policyStepups:"ofauth_policy_stepups",auditEvents:"ofauth_audit_events"},pe=[{name:o.identities,columns:[{name:"id",type:"string"},{name:"principal",type:"string",isIndexed:!0},{name:"secretHash",type:"string"},{name:"verifyMethod",type:"string",enum:["pin","password","custom"]},{name:"status",type:"string",enum:["active","disabled","locked"],isIndexed:!0},{name:"failedAttempts",type:"number"},{name:"lockoutUntil",type:"string",isOptional:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.assignments,columns:[{name:"id",type:"string"},{name:"identityId",type:"string",isIndexed:!0},{name:"roleRef",type:"string",isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"scopeAttributes",type:"json",isOptional:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.sessions,columns:[{name:"id",type:"string"},{name:"identityId",type:"string",isIndexed:!0},{name:"activeAssignmentId",type:"string",isOptional:!0,isIndexed:!0},{name:"assuranceLevel",type:"string",enum:["basic","elevated"],isIndexed:!0},{name:"issuedAt",type:"string"},{name:"expiresAt",type:"string",isIndexed:!0},{name:"revokedAt",type:"string",isOptional:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.policyProfiles,columns:[{name:"id",type:"string"},{name:"profileId",type:"string",isIndexed:!0},{name:"defaultAssuranceLevel",type:"string",enum:["basic","elevated"]},{name:"lockoutPolicyRef",type:"string"},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.policyStepups,columns:[{name:"id",type:"string"},{name:"actionRef",type:"string",isIndexed:!0},{name:"requiredAssuranceLevel",type:"string",enum:["basic","elevated"]},{name:"reauthWindowSeconds",type:"number",isOptional:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]},{name:o.auditEvents,columns:[{name:"id",type:"string"},{name:"eventType",type:"string",isIndexed:!0},{name:"identityId",type:"string",isOptional:!0,isIndexed:!0},{name:"sessionId",type:"string",isOptional:!0,isIndexed:!0},{name:"tenantId",type:"string",isOptional:!0,isIndexed:!0},{name:"branchId",type:"string",isOptional:!0,isIndexed:!0},{name:"scopeAttributes",type:"json",isOptional:!0},{name:"result",type:"string",enum:["success","failed"],isIndexed:!0},{name:"reasonCode",type:"string",isOptional:!0},{name:"timestamp",type:"string",isIndexed:!0},{name:"syncStatus",type:"string",enum:["pending","replayed"],isIndexed:!0},{name:"replayedAt",type:"string",isOptional:!0,isIndexed:!0},{name:"version",type:"number"},{name:"lastModified",type:"string"},{name:"deleted",type:"boolean",isIndexed:!0}]}],B={version:2,tables:pe};function _(){return B.tables}var G=5,V=900,k=480*60;function c(){return new Date().toISOString()}function g(r,e){return new Date(new Date(r).getTime()+e*1e3).toISOString()}function S(r){return new Date(r).getTime()<=Date.now()}function f(r){let e=0;return()=>(e+=1,`${r}-${Date.now()}-${e}`)}function W(r){return{identityId:r.id,principal:r.principal,status:r.status}}function K(r){return{assignmentId:r.id,identityId:r.identityId,roleRef:r.roleRef,scopeRef:{...r.tenantId?{tenantId:r.tenantId}:{},...r.branchId?{branchId:r.branchId}:{},...r.scopeAttributes?{attributes:r.scopeAttributes}:{}}}}function v(r,e){return{sessionId:r.id,identityId:r.identityId,activeScopeRef:e?{...e.tenantId?{tenantId:e.tenantId}:{},...e.branchId?{branchId:e.branchId}:{},...e.scopeAttributes?{attributes:e.scopeAttributes}:{}}:void 0,assuranceLevel:r.assuranceLevel,issuedAt:r.issuedAt,expiresAt:r.expiresAt}}async function $(r,e,t){return r?r.verifyPin(e,t):e===t}async function Q(r,e){var t,i,n,s,a,d;r.emitActivity&&await r.emitActivity({activityId:e.eventId,activityType:`ofauth.${e.eventType.toLowerCase()}`,occurredAt:e.timestamp,scopeRef:{domain:"ofauth",...(t=e.scopeRef)!=null&&t.tenantId?{tenantId:e.scopeRef.tenantId}:{},...(i=e.scopeRef)!=null&&i.branchId?{branchId:e.scopeRef.branchId}:{}},actor:e.identityId?{userId:e.identityId}:void 0,payload:{eventType:e.eventType,result:e.result,reasonCode:(n=e.reasonCode)!=null?n:null,sessionId:(s=e.sessionId)!=null?s:null,scopeAttributes:(d=(a=e.scopeRef)==null?void 0:a.attributes)!=null?d:null}})}async function y(r,e){if(!e)return null;let t=await r.get(o.assignments,e);return!t||t.deleted?null:t}function Y(){return[{profileId:"cashier_fast",defaultAssuranceLevel:"basic",lockoutPolicyRef:"default"},{profileId:"supervisor_strict",defaultAssuranceLevel:"elevated",lockoutPolicyRef:"strict"},{profileId:"member_self_service",defaultAssuranceLevel:"basic",lockoutPolicyRef:"member"}]}var b=class{constructor(e,t){this.db=e;this.options=t;this.newId=f("auth-audit")}async appendEvent(e){var i,n,s,a,d,u,l,A,R,q,M;let t={id:e.eventId||this.newId(),eventType:e.eventType,identityId:(i=e.identityId)!=null?i:null,sessionId:(n=e.sessionId)!=null?n:null,tenantId:(a=(s=e.scopeRef)==null?void 0:s.tenantId)!=null?a:null,branchId:(u=(d=e.scopeRef)==null?void 0:d.branchId)!=null?u:null,scopeAttributes:(A=(l=e.scopeRef)==null?void 0:l.attributes)!=null?A:null,result:e.result,reasonCode:(R=e.reasonCode)!=null?R:null,timestamp:e.timestamp,syncStatus:(q=e.syncStatus)!=null?q:"pending",replayedAt:(M=e.replayedAt)!=null?M:null,version:1,lastModified:c(),deleted:!1};await this.db.create(o.auditEvents,t),await Q(this.options,e)}async queryEvents(e){return(await this.db.query(o.auditEvents,{filters:{deleted:!1},sort:[{field:"timestamp",direction:"desc"}]})).filter(i=>e.identityId?i.identityId===e.identityId:!0).filter(i=>e.sessionId?i.sessionId===e.sessionId:!0).filter(i=>{var n;return(n=e.eventTypes)!=null&&n.length?e.eventTypes.includes(i.eventType):!0}).filter(i=>e.fromTimestamp?i.timestamp>=e.fromTimestamp:!0).filter(i=>e.toTimestamp?i.timestamp<=e.toTimestamp:!0).map(i=>{var n,s,a,d,u;return{eventId:i.id,eventType:i.eventType,identityId:(n=i.identityId)!=null?n:void 0,sessionId:(s=i.sessionId)!=null?s:void 0,scopeRef:i.tenantId||i.branchId||i.scopeAttributes?{...i.tenantId?{tenantId:i.tenantId}:{},...i.branchId?{branchId:i.branchId}:{},...i.scopeAttributes?{attributes:i.scopeAttributes}:{}}:void 0,result:i.result,reasonCode:(a=i.reasonCode)!=null?a:void 0,timestamp:i.timestamp,syncStatus:(d=i.syncStatus)!=null?d:"pending",replayedAt:(u=i.replayedAt)!=null?u:void 0}})}async listPendingReplay(e={}){var i;let t=await this.db.query(o.auditEvents,{filters:{deleted:!1},sort:[{field:"timestamp",direction:"asc"}]});return t.filter(n=>n.syncStatus!=="replayed").slice(0,(i=e.limit)!=null?i:t.length).map(n=>{var s,a,d,u,l;return{eventId:n.id,eventType:n.eventType,identityId:(s=n.identityId)!=null?s:void 0,sessionId:(a=n.sessionId)!=null?a:void 0,scopeRef:n.tenantId||n.branchId||n.scopeAttributes?{...n.tenantId?{tenantId:n.tenantId}:{},...n.branchId?{branchId:n.branchId}:{},...n.scopeAttributes?{attributes:n.scopeAttributes}:{}}:void 0,result:n.result,reasonCode:(d=n.reasonCode)!=null?d:void 0,timestamp:n.timestamp,syncStatus:(u=n.syncStatus)!=null?u:"pending",replayedAt:(l=n.replayedAt)!=null?l:void 0}})}async markReplayed(e,t=c()){let i=0;for(let n of e){let s=await this.db.get(o.auditEvents,n);!s||s.deleted||s.syncStatus==="replayed"||(await this.db.update(o.auditEvents,n,{syncStatus:"replayed",replayedAt:t,version:s.version+1,lastModified:c()}),i+=1)}return i}};var I=class extends Error{constructor(t,i,n=!1){super(i);this.code=t;this.retryable=n;this.name="OfauthDomainError"}};function m(r,e){return new I(r,e,!1)}function le(r){return new I("AUTH_NOT_IMPLEMENTED",r,!1)}var w=class{constructor(e,t){this.db=e;this.authAuditService=t;this.newEventId=f("auth-event")}async getActiveSessionOrThrow(e){let t=await this.db.get(o.sessions,e);if(!t||t.deleted||t.revokedAt||S(t.expiresAt))throw m("AUTH_SESSION_NOT_FOUND","Session not found");return t}async getPolicySnapshot(){let e=await this.db.query(o.policyProfiles,{filters:{deleted:!1},sort:[{field:"lastModified",direction:"desc"}]}),t=await this.db.query(o.policyStepups,{filters:{deleted:!1},sort:[{field:"lastModified",direction:"desc"}]});return{profiles:e.length>0?e.map(i=>({profileId:i.profileId,defaultAssuranceLevel:i.defaultAssuranceLevel,lockoutPolicyRef:i.lockoutPolicyRef})):Y(),stepUpRequirements:t.map(i=>{var n;return{actionRef:i.actionRef,requiredAssuranceLevel:i.requiredAssuranceLevel,reauthWindowSeconds:(n=i.reauthWindowSeconds)!=null?n:void 0}}),version:"1",updatedAt:c()}}async getStepUpRequirement(e){var i;let t=await this.db.query(o.policyStepups,{filters:{actionRef:e,deleted:!1},limit:1});return t[0]?{actionRef:t[0].actionRef,requiredAssuranceLevel:t[0].requiredAssuranceLevel,reauthWindowSeconds:(i=t[0].reauthWindowSeconds)!=null?i:void 0}:null}async evaluateStepUp(e,t){var d;let i=await this.getActiveSessionOrThrow(e),n=await this.getStepUpRequirement(t),s=(d=n==null?void 0:n.requiredAssuranceLevel)!=null?d:"basic",a=!h(i.assuranceLevel,s);return{actionRef:t,requiredAssuranceLevel:s,currentAssuranceLevel:i.assuranceLevel,requiresStepUp:a,reauthWindowSeconds:n==null?void 0:n.reauthWindowSeconds}}async enforceStepUp(e,t){let i=await this.getActiveSessionOrThrow(e),n=await this.evaluateStepUp(e,t);if(n.requiresStepUp)throw await this.authAuditService.appendEvent({eventId:this.newEventId(),eventType:"STEP_UP_CHALLENGED",identityId:i.identityId,sessionId:e,result:"failed",reasonCode:"AUTH_STEP_UP_REQUIRED",timestamp:c()}),m("AUTH_STEP_UP_REQUIRED",`Step-up required for action '${t}' (needs ${n.requiredAssuranceLevel})`)}async markStepUpPassed(e,t){var u;let i=await this.getActiveSessionOrThrow(e),n=await this.getStepUpRequirement(t),s=(u=n==null?void 0:n.requiredAssuranceLevel)!=null?u:"elevated";await this.db.update(o.sessions,e,{assuranceLevel:s,version:i.version+1,lastModified:c()}),await this.authAuditService.appendEvent({eventId:this.newEventId(),eventType:"STEP_UP_PASSED",identityId:i.identityId,sessionId:e,result:"success",reasonCode:t,timestamp:c()});let a=await this.db.get(o.sessions,e),d=a?await y(this.db,a.activeAssignmentId):null;if(!a)throw m("AUTH_SESSION_NOT_FOUND","Session not found");return v(a,d!=null?d:void 0)}};var C=class{constructor(e,t){this.db=e;this.authAuditService=t;this.newEventId=f("auth-event")}async listAssignments(e){return(await this.db.query(o.assignments,{filters:{identityId:e,deleted:!1},sort:[{field:"lastModified",direction:"desc"}]})).map(K)}async getActiveContext(e){let t=await this.db.get(o.sessions,e);if(!t||t.deleted||t.revokedAt||!t.activeAssignmentId)return null;let i=await y(this.db,t.activeAssignmentId);return i?{sessionId:e,assignmentId:i.id,scopeRef:{...i.tenantId?{tenantId:i.tenantId}:{},...i.branchId?{branchId:i.branchId}:{},...i.scopeAttributes?{attributes:i.scopeAttributes}:{}}}:null}async switchContext(e){let t=await this.db.get(o.sessions,e.sessionId);if(!t||t.deleted||t.revokedAt)throw m("AUTH_SESSION_NOT_FOUND","Session not found");let i=await y(this.db,e.targetAssignmentId);if(!i||i.identityId!==t.identityId)throw m("AUTH_CONTEXT_FORBIDDEN","Requested context is not assigned to this identity");let n=await this.db.update(o.sessions,e.sessionId,{activeAssignmentId:i.id,version:t.version+1,lastModified:c()});return await this.authAuditService.appendEvent({eventId:this.newEventId(),eventType:"CONTEXT_SWITCHED",identityId:t.identityId,sessionId:e.sessionId,scopeRef:{...i.tenantId?{tenantId:i.tenantId}:{},...i.branchId?{branchId:i.branchId}:{},...i.scopeAttributes?{attributes:i.scopeAttributes}:{}},result:"success",reasonCode:e.reasonCode,timestamp:n.lastModified}),{activeContext:{sessionId:e.sessionId,assignmentId:i.id,scopeRef:{...i.tenantId?{tenantId:i.tenantId}:{},...i.branchId?{branchId:i.branchId}:{},...i.scopeAttributes?{attributes:i.scopeAttributes}:{}}},requiresStepUp:!1,reasonCode:e.reasonCode}}};var x=class{constructor(e,t,i,n,s){this.db=e;this.options=t;this.sessionService=i;this.contextService=n;this.authAuditService=s;this.newEventId=f("auth-event")}async findIdentityByPrincipal(e){var i;return(i=(await this.db.query(o.identities,{filters:{principal:e,deleted:!1},limit:1}))[0])!=null?i:null}async persistFailedAttempt(e){let t=e.failedAttempts+1,i=t>=G,n=i?g(c(),V):null,s=i?"locked":e.status;return this.db.update(o.identities,e.id,{failedAttempts:t,lockoutUntil:n,status:s,version:e.version+1,lastModified:c()})}async clearFailedAttempt(e){e.failedAttempts===0&&!e.lockoutUntil&&e.status==="active"||await this.db.update(o.identities,e.id,{failedAttempts:0,lockoutUntil:null,status:"active",version:e.version+1,lastModified:c()})}async emitAudit(e){await this.authAuditService.appendEvent(e)}async verifyCredential(e){let t=await this.findIdentityByPrincipal(e.principal);if(!t)return await this.emitAudit({eventId:this.newEventId(),eventType:"LOGIN_FAILED",result:"failed",reasonCode:"INVALID_CREDENTIAL",timestamp:c()}),{ok:!1,reasonCode:"INVALID_CREDENTIAL",retryable:!0};if(t.status==="disabled")return await this.emitAudit({eventId:this.newEventId(),eventType:"LOGIN_FAILED",identityId:t.id,result:"failed",reasonCode:"IDENTITY_DISABLED",timestamp:c()}),{ok:!1,reasonCode:"IDENTITY_DISABLED",retryable:!1};if(t.lockoutUntil&&!S(t.lockoutUntil))return await this.emitAudit({eventId:this.newEventId(),eventType:"LOCKOUT_TRIGGERED",identityId:t.id,result:"failed",reasonCode:"IDENTITY_LOCKED",timestamp:c()}),{ok:!1,reasonCode:"IDENTITY_LOCKED",retryable:!1};if(!await $(this.options.platformAdapter,e.secret,t.secretHash)){let a=(await this.persistFailedAttempt(t)).status==="locked"?"IDENTITY_LOCKED":"INVALID_CREDENTIAL";return await this.emitAudit({eventId:this.newEventId(),eventType:a==="IDENTITY_LOCKED"?"LOCKOUT_TRIGGERED":"LOGIN_FAILED",identityId:t.id,result:"failed",reasonCode:a,timestamp:c()}),{ok:!1,reasonCode:a,retryable:a==="INVALID_CREDENTIAL"}}await this.clearFailedAttempt(t);let n=await this.contextService.listAssignments(t.id);return await this.emitAudit({eventId:this.newEventId(),eventType:"LOGIN_SUCCESS",identityId:t.id,scopeRef:e.scopeRef,result:"success",timestamp:c()}),{ok:!0,identity:W(t),assignments:n}}async login(e){let t=await this.verifyCredential({principal:e.principal,secret:e.secret,verifyMethod:e.verifyMethod});if(!t.ok)throw m("AUTH_INVALID_CREDENTIAL",`Authentication failed: ${t.reasonCode}`);let i=[...t.assignments].sort((s,a)=>s.assignmentId.localeCompare(a.assignmentId))[0],n=await this.sessionService.createSession({identityId:t.identity.identityId,assignmentId:i==null?void 0:i.assignmentId,assuranceLevel:"basic"});return{identity:t.identity,sessionId:n.sessionId}}async logout(e){await this.sessionService.revokeSession({sessionId:e,reasonCode:"LOGOUT"}),await this.emitAudit({eventId:this.newEventId(),eventType:"SESSION_REVOKED",sessionId:e,result:"success",reasonCode:"LOGOUT",timestamp:c()})}};var E=class{constructor(e,t){this.db=e;this.options=t;this.newId=f("auth-session")}async createSession(e){var a,d,u,l;let t=c(),i=g(t,(a=e.ttlSeconds)!=null?a:k),n=await this.db.create(o.sessions,{id:this.newId(),identityId:e.identityId,activeAssignmentId:(d=e.assignmentId)!=null?d:null,assuranceLevel:(u=e.assuranceLevel)!=null?u:"basic",issuedAt:t,expiresAt:i,revokedAt:null,version:1,lastModified:t,deleted:!1}),s=await y(this.db,n.activeAssignmentId);return(l=this.options.logger)==null||l.logInfo("[ofauth] session created",{sessionId:n.id,identityId:n.identityId}),v(n,s)}async refreshSession(e){var s;let t=await this.db.get(o.sessions,e.sessionId);if(!t||t.deleted||t.revokedAt)throw m("AUTH_SESSION_NOT_FOUND","Session not found");let i=await this.db.update(o.sessions,e.sessionId,{expiresAt:g(c(),(s=e.ttlSeconds)!=null?s:k),version:t.version+1,lastModified:c()}),n=await y(this.db,i.activeAssignmentId);return v(i,n)}async revokeSession(e){var i,n;let t=await this.db.get(o.sessions,e.sessionId);!t||t.deleted||t.revokedAt||(await this.db.update(o.sessions,e.sessionId,{revokedAt:c(),version:t.version+1,lastModified:c()}),(n=this.options.logger)==null||n.logInfo("[ofauth] session revoked",{sessionId:e.sessionId,reasonCode:(i=e.reasonCode)!=null?i:null}))}async getActiveSession(e){let t=await this.db.get(o.sessions,e);if(!t||t.deleted||t.revokedAt||S(t.expiresAt))return null;let i=await y(this.db,t.activeAssignmentId);return v(t,i)}};async function U(r,e={}){let t=new b(r,e),i=new E(r,e),n=new C(r,t),s=new w(r,t);return{identityService:new x(r,e,i,n,t),sessionService:i,contextService:n,authPolicyService:s,authAuditService:t}}var me="phase1-contract-only";var z=require("ofcore"),H=require("ofcore"),P=require("ofcore");var N=[{toVersion:1,up:async r=>{let e=_();for(let t of e)try{await r.addTable(t)}catch{}}},{toVersion:2,up:async r=>{try{await r.addColumn(o.auditEvents,{name:"syncStatus",type:"string",enum:["pending","replayed"],isIndexed:!0})}catch{}try{await r.addColumn(o.auditEvents,{name:"replayedAt",type:"string",isOptional:!0,isIndexed:!0})}catch{}}}];var fe={logInfo(){},logWarn(){},logError(){}};async function F(r,e=fe){e.logInfo("[ofauth] starting database migration process");let t=[...N].sort((s,a)=>s.toVersion-a.toVersion),i=t.length>0?t[t.length-1].toVersion:0,n=await r.getSchemaVersion();if((n==null||n<0)&&(n=0),n>=i){e.logInfo(`[ofauth] database already up-to-date at v${n}`);return}for(let s of t)s.toVersion>n&&(e.logInfo(`[ofauth] applying migration v${s.toVersion}`),await s.up(r),await r.setSchemaVersion(s.toVersion),n=s.toVersion);e.logInfo(`[ofauth] migration completed at v${n}`)}var O=class{constructor(e,t){this.runtime=e;this.runtimeStateStore=t;this.runtimeStore=(0,P.asReadonlyStore)(this.runtimeStateStore)}static builder(){return new T}get registry(){return this.runtime.registry}async start(e={}){this.runtimeStateStore.setState({phase:"starting",started:!1,lastError:null,lastTransitionAt:new Date().toISOString()});try{await this.runtime.start(e),this.domainServices=this.runtime.domainServices,this.runtimeStateStore.setState(t=>({...t,phase:"started",started:!0,startCount:t.startCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(t){throw this.runtimeStateStore.setState({phase:"error",started:!1,lastError:t instanceof Error?t.message:String(t),lastTransitionAt:new Date().toISOString()}),t}}async init(e={}){this.runtimeStateStore.setState({phase:"starting",started:!1,lastError:null,lastTransitionAt:new Date().toISOString()});try{await this.runtime.init(e),this.domainServices=this.runtime.domainServices,this.runtimeStateStore.setState(t=>({...t,phase:"started",started:!0,startCount:t.startCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(t){throw this.runtimeStateStore.setState({phase:"error",started:!1,lastError:t instanceof Error?t.message:String(t),lastTransitionAt:new Date().toISOString()}),t}}async stop(){this.runtimeStateStore.setState({phase:"stopping",started:this.runtime.isStarted(),lastError:null,lastTransitionAt:new Date().toISOString()});try{await this.runtime.stop(),this.runtimeStateStore.setState(e=>({...e,phase:"stopped",started:!1,stopCount:e.stopCount+1,lastError:null,lastTransitionAt:new Date().toISOString()}))}catch(e){throw this.runtimeStateStore.setState({phase:"error",started:this.runtime.isStarted(),lastError:e instanceof Error?e.message:String(e),lastTransitionAt:new Date().toISOString()}),e}}isStarted(){return this.runtime.isStarted()}},T=class{constructor(){this.runtimeBuilder=z.CoreRuntime.builder();this.domainServiceOverrides={};this.runtimeHooks={};this.runtimeBuilder.withDbAdapter(()=>new H.InMemoryDbAdapter)}withPlatformAdapter(e){return this.runtimeBuilder.withPlatformAdapter(e),this}withDbAdapter(e){return this.runtimeBuilder.withDbAdapter(e),this}withHttpAdapter(e){return this.runtimeBuilder.withHttpAdapter(e),this}withSocketAdapter(e){return this.runtimeBuilder.withSocketAdapter(e),this}withLoggerAdapter(e){return this.runtimeBuilder.withLoggerAdapter(e),this}withActivitySink(e){return this.runtimeBuilder.withActivitySink(e),this}withExtension(e,t){return this.runtimeBuilder.withExtension(e,t),this}withDomainServicesFactory(e){return this.domainServicesFactory=e,this}overrideDomainServices(e){return this.domainServiceOverrides={...this.domainServiceOverrides,...e},this}withRuntimeHooks(e){return this.runtimeHooks={...this.runtimeHooks,...e},this}withMigrationRunner(e){return this.withRuntimeHooks({runMigrations:e})}withSeedRunner(e){return this.withRuntimeHooks({runSeed:e})}build(){var n;let e=(0,P.createStore)({phase:"idle",started:!1,startCount:0,stopCount:0,lastError:null,lastTransitionAt:new Date().toISOString()}),t=async s=>{var d,u;let a=(d=s.registry)==null?void 0:d.dbAdapter;a&&await F(a,(u=s.registry)==null?void 0:u.loggerAdapter)};this.runtimeBuilder.withHooks({...this.runtimeHooks,runMigrations:(n=this.runtimeHooks.runMigrations)!=null?n:t,createDomainServices:async s=>{var d,u,l,A;return{...this.domainServicesFactory?await this.domainServicesFactory():await U((u=(d=s.registry)==null?void 0:d.dbAdapter)!=null?u:new H.InMemoryDbAdapter,{logger:(l=s.registry)==null?void 0:l.loggerAdapter,platformAdapter:(A=s.registry)==null?void 0:A.platformAdapter,emitActivity:async R=>{await s.emitActivity(R)}}),...this.domainServiceOverrides}}});let i=this.runtimeBuilder.build();return new O(i,e)}};
package/package.json CHANGED
@@ -1,16 +1,28 @@
1
1
  {
2
2
  "name": "ofauth-shared-core",
3
- "version": "0.1.0-alpha.0",
3
+ "version": "0.1.0-alpha.1",
4
4
  "private": false,
5
5
  "description": "Offline-first auth shared-core (identity/session/context/assurance) for of* domain modules.",
6
+ "author": {
7
+ "name": "Agus Made",
8
+ "email": "krisnaparta@gmail.com"
9
+ },
6
10
  "main": "dist/index.js",
11
+ "module": "dist/index.esm.js",
7
12
  "types": "dist/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.esm.js",
17
+ "require": "./dist/index.js"
18
+ }
19
+ },
8
20
  "files": [
9
21
  "dist"
10
22
  ],
11
23
  "scripts": {
12
24
  "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
13
- "build": "npm run clean && tsc -p tsconfig.build.json",
25
+ "build": "npm run clean && tsc -p tsconfig.build.json && node esbuild.config.js",
14
26
  "typecheck": "tsc -p tsconfig.json --noEmit",
15
27
  "test": "NODE_PATH=.. npm run build && NODE_PATH=.. node --test ./tests/*.test.js",
16
28
  "verify:contract": "node ./scripts/verify-surface.js",
@@ -19,17 +31,15 @@
19
31
  "verify:factory-boundary": "node ./scripts/verify-no-service-logic-in-factory.js",
20
32
  "ci:check": "npm run typecheck && npm run verify:contract && npm run test && npm run verify:logic && npm run verify:factory-boundary",
21
33
  "prepublishOnly": "npm run ci:check",
22
- "prepack": "npm run build"
34
+ "prepack": "npm run build",
35
+ "bundle": "node esbuild.config.js"
23
36
  },
24
37
  "dependencies": {
25
38
  "ofcore": "0.1.0-alpha.0"
26
39
  },
27
40
  "devDependencies": {
28
- "typescript": "^5.9.3"
29
- },
30
- "author": {
31
- "name": "Agus Made",
32
- "email": "krisnaparta@gmail.com"
41
+ "typescript": "^5.9.3",
42
+ "esbuild": "^0.25.11"
33
43
  },
34
44
  "publishConfig": {
35
45
  "access": "public"
@@ -1,200 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OfauthCoreBuilder = exports.OfauthCore = void 0;
4
- const ofcore_1 = require("ofcore");
5
- const ofcore_2 = require("ofcore");
6
- const ofcore_3 = require("ofcore");
7
- const createDbAdapterOfauthServices_1 = require("./services/createDbAdapterOfauthServices");
8
- const applyPendingMigrations_1 = require("./data/applyPendingMigrations");
9
- class OfauthCore {
10
- constructor(runtime, runtimeStateStore) {
11
- this.runtime = runtime;
12
- this.runtimeStateStore = runtimeStateStore;
13
- this.runtimeStore = (0, ofcore_3.asReadonlyStore)(this.runtimeStateStore);
14
- }
15
- static builder() {
16
- return new OfauthCoreBuilder();
17
- }
18
- get registry() {
19
- return this.runtime.registry;
20
- }
21
- async start(options = {}) {
22
- this.runtimeStateStore.setState({
23
- phase: 'starting',
24
- started: false,
25
- lastError: null,
26
- lastTransitionAt: new Date().toISOString(),
27
- });
28
- try {
29
- await this.runtime.start(options);
30
- this.domainServices = this.runtime.domainServices;
31
- this.runtimeStateStore.setState((state) => ({
32
- ...state,
33
- phase: 'started',
34
- started: true,
35
- startCount: state.startCount + 1,
36
- lastError: null,
37
- lastTransitionAt: new Date().toISOString(),
38
- }));
39
- }
40
- catch (error) {
41
- this.runtimeStateStore.setState({
42
- phase: 'error',
43
- started: false,
44
- lastError: error instanceof Error ? error.message : String(error),
45
- lastTransitionAt: new Date().toISOString(),
46
- });
47
- throw error;
48
- }
49
- }
50
- async init(options = {}) {
51
- this.runtimeStateStore.setState({
52
- phase: 'starting',
53
- started: false,
54
- lastError: null,
55
- lastTransitionAt: new Date().toISOString(),
56
- });
57
- try {
58
- await this.runtime.init(options);
59
- this.domainServices = this.runtime.domainServices;
60
- this.runtimeStateStore.setState((state) => ({
61
- ...state,
62
- phase: 'started',
63
- started: true,
64
- startCount: state.startCount + 1,
65
- lastError: null,
66
- lastTransitionAt: new Date().toISOString(),
67
- }));
68
- }
69
- catch (error) {
70
- this.runtimeStateStore.setState({
71
- phase: 'error',
72
- started: false,
73
- lastError: error instanceof Error ? error.message : String(error),
74
- lastTransitionAt: new Date().toISOString(),
75
- });
76
- throw error;
77
- }
78
- }
79
- async stop() {
80
- this.runtimeStateStore.setState({
81
- phase: 'stopping',
82
- started: this.runtime.isStarted(),
83
- lastError: null,
84
- lastTransitionAt: new Date().toISOString(),
85
- });
86
- try {
87
- await this.runtime.stop();
88
- this.runtimeStateStore.setState((state) => ({
89
- ...state,
90
- phase: 'stopped',
91
- started: false,
92
- stopCount: state.stopCount + 1,
93
- lastError: null,
94
- lastTransitionAt: new Date().toISOString(),
95
- }));
96
- }
97
- catch (error) {
98
- this.runtimeStateStore.setState({
99
- phase: 'error',
100
- started: this.runtime.isStarted(),
101
- lastError: error instanceof Error ? error.message : String(error),
102
- lastTransitionAt: new Date().toISOString(),
103
- });
104
- throw error;
105
- }
106
- }
107
- isStarted() {
108
- return this.runtime.isStarted();
109
- }
110
- }
111
- exports.OfauthCore = OfauthCore;
112
- class OfauthCoreBuilder {
113
- constructor() {
114
- this.runtimeBuilder = ofcore_1.CoreRuntime.builder();
115
- this.domainServiceOverrides = {};
116
- this.runtimeHooks = {};
117
- this.runtimeBuilder.withDbAdapter(() => new ofcore_2.InMemoryDbAdapter());
118
- }
119
- withPlatformAdapter(factory) {
120
- this.runtimeBuilder.withPlatformAdapter(factory);
121
- return this;
122
- }
123
- withDbAdapter(factory) {
124
- this.runtimeBuilder.withDbAdapter(factory);
125
- return this;
126
- }
127
- withHttpAdapter(factory) {
128
- this.runtimeBuilder.withHttpAdapter(factory);
129
- return this;
130
- }
131
- withSocketAdapter(factory) {
132
- this.runtimeBuilder.withSocketAdapter(factory);
133
- return this;
134
- }
135
- withLoggerAdapter(factory) {
136
- this.runtimeBuilder.withLoggerAdapter(factory);
137
- return this;
138
- }
139
- withActivitySink(factory) {
140
- this.runtimeBuilder.withActivitySink(factory);
141
- return this;
142
- }
143
- withExtension(name, factory) {
144
- this.runtimeBuilder.withExtension(name, factory);
145
- return this;
146
- }
147
- withDomainServicesFactory(factory) {
148
- this.domainServicesFactory = factory;
149
- return this;
150
- }
151
- overrideDomainServices(overrides) {
152
- this.domainServiceOverrides = { ...this.domainServiceOverrides, ...overrides };
153
- return this;
154
- }
155
- withRuntimeHooks(hooks) {
156
- this.runtimeHooks = { ...this.runtimeHooks, ...hooks };
157
- return this;
158
- }
159
- withMigrationRunner(runner) {
160
- return this.withRuntimeHooks({ runMigrations: runner });
161
- }
162
- withSeedRunner(runner) {
163
- return this.withRuntimeHooks({ runSeed: runner });
164
- }
165
- build() {
166
- const runtimeStateStore = (0, ofcore_3.createStore)({
167
- phase: 'idle',
168
- started: false,
169
- startCount: 0,
170
- stopCount: 0,
171
- lastError: null,
172
- lastTransitionAt: new Date().toISOString(),
173
- });
174
- const defaultRunMigrations = async (runtime) => {
175
- const dbAdapter = runtime.registry?.dbAdapter;
176
- if (!dbAdapter)
177
- return;
178
- await (0, applyPendingMigrations_1.applyPendingMigrations)(dbAdapter, runtime.registry?.loggerAdapter);
179
- };
180
- this.runtimeBuilder.withHooks({
181
- ...this.runtimeHooks,
182
- runMigrations: this.runtimeHooks.runMigrations ?? defaultRunMigrations,
183
- createDomainServices: async (runtime) => {
184
- const base = this.domainServicesFactory
185
- ? await this.domainServicesFactory()
186
- : await (0, createDbAdapterOfauthServices_1.createDbAdapterOfauthServices)(runtime.registry?.dbAdapter ?? new ofcore_2.InMemoryDbAdapter(), {
187
- logger: runtime.registry?.loggerAdapter,
188
- platformAdapter: runtime.registry?.platformAdapter,
189
- emitActivity: async (record) => {
190
- await runtime.emitActivity(record);
191
- },
192
- });
193
- return { ...base, ...this.domainServiceOverrides };
194
- },
195
- });
196
- const runtime = this.runtimeBuilder.build();
197
- return new OfauthCore(runtime, runtimeStateStore);
198
- }
199
- }
200
- exports.OfauthCoreBuilder = OfauthCoreBuilder;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isAuthAuditEventType = isAuthAuditEventType;
4
- function isAuthAuditEventType(value) {
5
- const allowed = [
6
- 'LOGIN_SUCCESS',
7
- 'LOGIN_FAILED',
8
- 'LOCKOUT_TRIGGERED',
9
- 'SESSION_REVOKED',
10
- 'CONTEXT_SWITCHED',
11
- 'STEP_UP_CHALLENGED',
12
- 'STEP_UP_PASSED',
13
- 'STEP_UP_FAILED',
14
- ];
15
- return allowed.includes(value);
16
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,8 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasAnyScopeDimension = hasAnyScopeDimension;
4
- function hasAnyScopeDimension(scope) {
5
- return Boolean(scope.tenantId ||
6
- scope.branchId ||
7
- (scope.attributes && Object.keys(scope.attributes).length > 0));
8
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isAssuranceLevelAtLeast = isAssuranceLevelAtLeast;
4
- function isAssuranceLevelAtLeast(current, required) {
5
- const rank = {
6
- basic: 1,
7
- elevated: 2,
8
- };
9
- return rank[current] >= rank[required];
10
- }
@@ -1,30 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.applyPendingMigrations = applyPendingMigrations;
4
- const migrations_1 = require("./migrations");
5
- const noopLogger = {
6
- logInfo() { },
7
- logWarn() { },
8
- logError() { },
9
- };
10
- async function applyPendingMigrations(adapter, logger = noopLogger) {
11
- logger.logInfo('[ofauth] starting database migration process');
12
- const sorted = [...migrations_1.migrations].sort((a, b) => a.toVersion - b.toVersion);
13
- const targetVersion = sorted.length > 0 ? sorted[sorted.length - 1].toVersion : 0;
14
- let currentVersion = await adapter.getSchemaVersion();
15
- if (currentVersion == null || currentVersion < 0)
16
- currentVersion = 0;
17
- if (currentVersion >= targetVersion) {
18
- logger.logInfo(`[ofauth] database already up-to-date at v${currentVersion}`);
19
- return;
20
- }
21
- for (const migration of sorted) {
22
- if (migration.toVersion > currentVersion) {
23
- logger.logInfo(`[ofauth] applying migration v${migration.toVersion}`);
24
- await migration.up(adapter);
25
- await adapter.setSchemaVersion(migration.toVersion);
26
- currentVersion = migration.toVersion;
27
- }
28
- }
29
- logger.logInfo(`[ofauth] migration completed at v${currentVersion}`);
30
- }
@@ -1,47 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.migrations = void 0;
4
- const schemas_1 = require("./schemas");
5
- exports.migrations = [
6
- {
7
- toVersion: 1,
8
- up: async (adapter) => {
9
- const tables = (0, schemas_1.getOfauthTableSchemas)();
10
- for (const table of tables) {
11
- try {
12
- await adapter.addTable(table);
13
- }
14
- catch {
15
- // keep migration idempotent for adapters that throw when table exists
16
- }
17
- }
18
- },
19
- },
20
- {
21
- toVersion: 2,
22
- up: async (adapter) => {
23
- try {
24
- await adapter.addColumn(schemas_1.OFAUTH_TABLES.auditEvents, {
25
- name: 'syncStatus',
26
- type: 'string',
27
- enum: ['pending', 'replayed'],
28
- isIndexed: true,
29
- });
30
- }
31
- catch {
32
- // keep migration idempotent
33
- }
34
- try {
35
- await adapter.addColumn(schemas_1.OFAUTH_TABLES.auditEvents, {
36
- name: 'replayedAt',
37
- type: 'string',
38
- isOptional: true,
39
- isIndexed: true,
40
- });
41
- }
42
- catch {
43
- // keep migration idempotent
44
- }
45
- },
46
- },
47
- ];