@aiquants/auth-directory-drizzle 0.6.1 → 0.7.0
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.d.mts +862 -219
- package/dist/index.d.ts +862 -219
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var J=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var me=Object.getOwnPropertyNames;var ye=Object.prototype.hasOwnProperty;var ge=(t,n)=>{for(var g in n)J(t,g,{get:n[g],enumerable:!0})},he=(t,n,g,u)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of me(n))!ye.call(t,i)&&i!==g&&J(t,i,{get:()=>n[i],enumerable:!(u=ce(n,i))||u.enumerable});return t};var be=t=>he(J({},"__esModule",{value:!0}),t);var _e={};ge(_e,{AUTH_DIRECTORY_PROVIDER_COLUMN:()=>ue,AUTH_DIRECTORY_TENANT_SCOPED_TABLES:()=>xe,MAX_IN_LIST:()=>Be,MAX_PARAMETERS:()=>de,MEMBERSHIP_MODES:()=>X,UNHEALTHY_SYNC_OUTCOMES:()=>re,assertGroupMayBeLinked:()=>Ie,assertMembershipMode:()=>K,chunk:()=>L,chunkByParameters:()=>N,createDirectoryLinkStore:()=>Se,createDirectorySync:()=>Ge,createDirectorySyncRepository:()=>Pe,createPromotionRepository:()=>De,createSyncRequestQueue:()=>Re,defaultExternalGroupGuardMessage:()=>we,defaultSyncMessages:()=>ee,defineAuthDirectorySchema:()=>ke,findLedgerRowsForIdentity:()=>q,promoteLedgerForUser:()=>Ae,withExternalGroupGuards:()=>fe});module.exports=be(_e);var oe=require("@aiquants/authz-core"),we=(t,n)=>`\u5916\u90E8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u9023\u643A\u30B0\u30EB\u30FC\u30D7 (${n}) \u306B\u306F\u7BA1\u7406\u30ED\u30FC\u30EB (${t}) \u3092\u6301\u305F\u305B\u3089\u308C\u307E\u305B\u3093\u3002\u4E0A\u6D41\u5074\u306E\u6240\u5C5E\u5909\u66F4\u304C\u305D\u306E\u307E\u307E\u7BA1\u7406\u8005\u306E\u5897\u6E1B\u306B\u306A\u308B\u305F\u3081\u3001\u7BA1\u7406\u8005\u7D4C\u8DEF\u306F\u30ED\u30FC\u30AB\u30EB\u7BA1\u7406\u306E\u30B0\u30EB\u30FC\u30D7\u306B\u9650\u5B9A\u3057\u3066\u3044\u307E\u3059\u3002`;function z(t,n,g,u){return new Set(t.filter(i=>n.has(i.roleId)&&i.appKey===g&&i.resourceKey===u).map(i=>i.action))}function V(t,n){return new Set(t.filter(g=>g.groupId===n).map(g=>g.roleId))}var B=t=>oe.AUTHZ_ACTIONS.every(n=>t.has(n)),W=(t,n)=>t.find(g=>g.roleId===n)?.roleKey??`#${n}`;function Y(t,n,g,u){let i=[...n].find(c=>B(z(t,new Set([c]),g,u)));return i!==void 0?W(t,i):[...n].filter(c=>z(t,new Set([c]),g,u).size>0).map(c=>W(t,c)).join(" + ")}function fe(t,n){return ie(t,n)}function ie(t,n){let g=t;return{...t,withTransaction:(u,i)=>g.withTransaction((l,c)=>u(ie(l,n),c),i),async assignGroupRole(u,i,l,c){await g.withTransaction(async(b,f)=>{let o=await b.listGrants(u),h=V(await b.listGroupRoles(u),i);if(h.add(l),B(z(o,h,n.adminAppKey,n.adminResourceKey))){let e=await n.linkLookup.externalGroupKey(u,i,f);if(e!==null)throw new Error(n.message(Y(o,h,n.adminAppKey,n.adminResourceKey),e))}await b.assignGroupRole(u,i,l,c)})},async createGrant(u,i,l){await g.withTransaction(async(c,b)=>{let o=(await c.listResources(u)).find(h=>h.id===i.resourceId);if(o?.appKey===n.adminAppKey&&o?.resourceKey===n.adminResourceKey){let h=await c.listGrants(u),e=await c.listGroupRoles(u);for(let p of new Set(e.filter(w=>w.roleId===i.roleId).map(w=>w.groupId))){let w=z(h,V(e,p),n.adminAppKey,n.adminResourceKey);if(w.add(i.action),!B(w))continue;let a=await n.linkLookup.externalGroupKey(u,p,b);if(a!==null)throw new Error(n.message(Y(h,V(e,p),n.adminAppKey,n.adminResourceKey)||W(h,i.roleId),a))}}await c.createGrant(u,i,l)})}}}async function Ie(t,n,g,u){let i=(await t.listGroupRoles(n)).filter(f=>f.groupId===g);if(i.length===0)return;let l=await t.listGrants(n),c=new Set(i.map(f=>f.roleId));if(!B(z(l,c,u.adminAppKey,u.adminResourceKey)))return;let b=i[0];if(b)throw new Error(u.message(Y(l,c,u.adminAppKey,u.adminResourceKey),b.groupKey))}var $=require("drizzle-orm");async function q(t,n,g){let{ledger:u,group:i}=n,{tenantId:l,externalUserId:c,email:b}=g;if(c===null&&b==="")return[];let f={ledgerId:u.id,groupId:u.groupId,tenantId:i.tenantId,externalUserId:u.externalUserId},o=async a=>(await t.select(f).from(u).innerJoin(i,(0,$.and)((0,$.eq)(i.id,u.groupId),(0,$.eq)(i.tenantId,l),(0,$.eq)(i.isActive,!0))).where(a)).map(S=>({ledgerId:Number(S.ledgerId),groupId:Number(S.groupId),tenantId:String(S.tenantId),externalUserId:S.externalUserId===null?null:String(S.externalUserId)})),h=a=>{let v=new Map;for(let S of a)v.set(S.ledgerId,{ledgerId:S.ledgerId,groupId:S.groupId,tenantId:S.tenantId});return[...v.values()].sort((S,T)=>S.ledgerId-T.ledgerId)},e=c===null?[]:await o((0,$.eq)(u.externalUserId,c));if(b==="")return h(e);let p=await o((0,$.eq)(u.email,b)),w=a=>c!==null&&a.externalUserId!==null&&a.externalUserId!==c;return h([...e,...p.filter(a=>!w(a))])}var C=require("@aiquants/auth-core"),se=require("@aiquants/auth-directory-core"),x=require("@aiquants/authz-core"),d=require("drizzle-orm");var X=["direct","transitive"];function K(t){if(!X.includes(t))throw new TypeError(`[@aiquants/auth-directory-drizzle] membershipMode must be one of ${X.join(" | ")}, received ${JSON.stringify(t)}`);return t}function Se(t,n,g,u){let i=t,l=u.ensureConnection??(async()=>{}),c=u.policyCacheTtlMs??0;if(!Number.isFinite(c)||c<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] policyCacheTtlMs must be a non-negative number, received ${String(u.policyCacheTtlMs)}`);let b=new Map,f=r=>b.delete(r),{TDGroupExternalLink:o,TDGroupMemberEmail:h,TDTenantMembershipGroup:e,TDAllowlistGroup:p,TDDirectorySyncRequest:w}=n,{TMGroup:a,TDGroupMember:v}=g;async function S(r,s,y){if((await r.select({groupId:e.groupId}).from(e).where((0,d.and)((0,d.eq)(e.tenantId,s),(0,d.eq)(e.groupId,y),(0,d.eq)(e.isBreakGlass,!0)))).length>0)throw new Error(`Group ${y} is a break-glass proof group; a break-glass proof path must be one the synchronization can never touch.`)}async function T(r,s,y){let[I]=await r.select({id:a.id}).from(a).where((0,d.and)((0,d.eq)(a.id,y),(0,d.eq)(a.tenantId,s)));if(!I)throw new Error(`Group not found in tenant: ${y}`)}function G(r,s){return{linkId:Number(r.linkId),groupId:Number(r.groupId),tenantId:String(r.tenantId),provider:String(r.provider),externalId:String(r.externalId),externalKey:String(r.externalKey),membershipMode:K(String(r.membershipMode)),isSyncEnabled:!!r.isSyncEnabled,...r.syncedAt?{syncedAt:new Date(r.syncedAt).toISOString()}:{},...r.syncError?{syncError:String(r.syncError)}:{},unresolvedCount:s}}async function _(r,s){let y=await r.select({groupId:h.groupId,n:(0,d.count)()}).from(h).innerJoin(a,(0,d.and)((0,d.eq)(a.id,h.groupId),(0,d.eq)(a.tenantId,s))).where((0,d.isNull)(h.resolvedUserId)).groupBy(h.groupId);return new Map(y.map(I=>[Number(I.groupId),Number(I.n)]))}return{async listLinks(r){(0,x.assertTenantId)(r,"listLinks(tenantId)"),await l();let s=await i.select({linkId:o.id,groupId:o.groupId,tenantId:o.tenantId,provider:o.provider,externalId:o.externalId,externalKey:o.externalKey,membershipMode:o.membershipMode,isSyncEnabled:o.isSyncEnabled,syncedAt:o.syncedAt,syncError:o.syncError}).from(o).where((0,d.eq)(o.tenantId,r)).orderBy((0,d.asc)(o.groupId)),y=await _(i,r);return s.map(I=>((0,x.assertTenantMatch)(r,String(I.tenantId),"listLinks(row.tenantId)"),G(I,y.get(Number(I.groupId))??0)))},async externalGroupKey(r,s,y){(0,x.assertTenantId)(r,"externalGroupKey(tenantId)"),await l();let[I]=await(y??i).select({externalKey:o.externalKey}).from(o).where((0,d.and)((0,d.eq)(o.groupId,s),(0,d.eq)(o.tenantId,r)));return I?String(I.externalKey):null},async linkGroup(r,s,y,I){(0,x.assertTenantId)(r,"linkGroup(tenantId)");let D=K(y.membershipMode),k=y.externalId.trim(),R=(0,C.normalizeAuthEmail)(y.externalKey);if(k===""||R==="")throw new TypeError("[@aiquants/auth-directory-drizzle] externalId and externalKey must be non-empty");await l(),await u.linkable.assertLinkableAndWrite(r,s,async H=>{let E=H;await T(E,r,s),await S(E,r,s),await E.insert(o).output().values({groupId:s,tenantId:r,provider:y.provider,externalId:k,externalKey:R,membershipMode:D,isSyncEnabled:!0,vanishedObservations:0,createdAt:new Date,createdBy:I})}),f(r)},async unlinkGroup(r,s){(0,x.assertTenantId)(r,"unlinkGroup(tenantId)"),await l(),await i.transaction(async y=>{await T(y,r,s),await y.delete(h).where((0,d.eq)(h.groupId,s)),await y.delete(p).where((0,d.and)((0,d.eq)(p.groupId,s),(0,d.eq)(p.tenantId,r))),await y.delete(o).where((0,d.and)((0,d.eq)(o.groupId,s),(0,d.eq)(o.tenantId,r)))}),f(r)},async setSyncEnabled(r,s,y,I){(0,x.assertTenantId)(r,"setSyncEnabled(tenantId)"),await l(),await i.update(o).set({isSyncEnabled:y,updatedAt:new Date,updatedBy:I}).output().where((0,d.and)((0,d.eq)(o.groupId,s),(0,d.eq)(o.tenantId,r)))},async requestSync(r,s,y){(0,x.assertTenantId)(r,"requestSync(tenantId)"),await l(),await i.transaction(async I=>{s!==null&&await T(I,r,s),await I.insert(w).output().values({tenantId:r,groupId:s,requestedBy:y,requestedAt:new Date,createdAt:new Date,createdBy:y})})},async getStatus(r){(0,x.assertTenantId)(r,"getStatus(tenantId)"),await l();let s=await i.select({groupId:o.groupId,isSyncEnabled:o.isSyncEnabled,syncedAt:o.syncedAt,syncError:o.syncError}).from(o).where((0,d.eq)(o.tenantId,r)),[y]=await i.select({n:(0,d.count)()}).from(w).where((0,d.and)((0,d.eq)(w.tenantId,r),(0,d.isNull)(w.finishedAt))),I=s.filter(E=>!!E.isSyncEnabled),D=I.map(E=>E.syncedAt?new Date(E.syncedAt).getTime():null),k=D.length>0&&D.every(E=>E!==null)?Math.min(...D):null,H=s.length>0&&I.length===0||I.length>0&&(k===null||Date.now()-k>u.stalenessThresholdSec*1e3);return{isEnabled:u.isEnabled,provider:u.provider,linkedGroupCount:s.length,...k!==null?{oldestSyncedAt:new Date(k).toISOString()}:{},isStale:H,pausedGroupCount:s.length-I.length,stalenessThresholdSec:u.stalenessThresholdSec,erroredGroupIds:s.filter(E=>!!E.syncError).map(E=>Number(E.groupId)).sort((E,pe)=>E-pe),pendingRequestCount:Number(y?.n??0)}},async loadTenantMembershipPolicy(r){(0,x.assertTenantId)(r,"loadTenantMembershipPolicy(tenantId)");let s=c>0?b.get(r):void 0;if(s&&Date.now()-s.loadedAt<c)return s.policy;await l();let y=await i.select({groupId:e.groupId,isBreakGlass:e.isBreakGlass,externalLinkId:o.id}).from(e).innerJoin(a,(0,d.and)((0,d.eq)(a.id,e.groupId),(0,d.eq)(a.tenantId,r))).leftJoin(o,(0,d.eq)(o.groupId,e.groupId)).where((0,d.eq)(e.tenantId,r));if(y.length===0){let R={kind:"no-proof-required"};return c>0&&b.set(r,{policy:R,loadedAt:Date.now()}),R}let I=y.map(R=>Number(R.groupId)),D=y.filter(R=>!!R.isBreakGlass);for(let R of D)if(R.externalLinkId!==null)throw new Error(`Break-glass group ${Number(R.groupId)} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`);let k={kind:"require-proof",proofGroupIds:I,breakGlassGroupIds:D.map(R=>Number(R.groupId))};return(0,se.assertTenantMembershipPolicy)(k,`tenant ${r}`),c>0&&b.set(r,{policy:k,loadedAt:Date.now()}),k},async setTenantMembershipGroup(r,s,y,I){(0,x.assertTenantId)(r,"setTenantMembershipGroup(tenantId)"),await l(),await i.transaction(async D=>{if(await T(D,r,s),y){let[R]=await D.select({id:o.id}).from(o).where((0,d.and)((0,d.eq)(o.tenantId,r),(0,d.eq)(o.groupId,s)));if(R)throw new Error(`Group ${s} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`)}if((await D.select({groupId:e.groupId}).from(e).where((0,d.and)((0,d.eq)(e.tenantId,r),(0,d.eq)(e.groupId,s)))).length>0){await D.update(e).set({isBreakGlass:y,updatedAt:new Date,updatedBy:I}).output().where((0,d.and)((0,d.eq)(e.tenantId,r),(0,d.eq)(e.groupId,s))),f(r);return}await D.insert(e).output().values({tenantId:r,groupId:s,isBreakGlass:y,createdAt:new Date,createdBy:I})}),f(r)},async removeTenantMembershipGroup(r,s){(0,x.assertTenantId)(r,"removeTenantMembershipGroup(tenantId)"),await l(),await i.transaction(async y=>{let D=(await y.select({groupId:e.groupId,isBreakGlass:e.isBreakGlass}).from(e).where((0,d.eq)(e.tenantId,r))).filter(k=>Number(k.groupId)!==s);if(D.length>0&&!D.some(k=>!!k.isBreakGlass))throw new Error(`Removing group ${s} would leave tenant ${r} with a membership proof but no break-glass path.`);await y.delete(e).where((0,d.and)((0,d.eq)(e.tenantId,r),(0,d.eq)(e.groupId,s)))}),f(r)},async setGroupActive(r,s,y,I){(0,x.assertTenantId)(r,"setGroupActive(tenantId)"),await l(),await i.update(a).set({isActive:y,updatedAt:new Date,updatedBy:I}).output().where((0,d.and)((0,d.eq)(a.id,s),(0,d.eq)(a.tenantId,r)))},async listLedgerGroupIds(r,s){if((0,x.assertTenantId)(r,"listLedgerGroupIds(tenantId)"),!u.isEnabled)return[];await l();let y=await q(i,{ledger:h,group:a},{tenantId:r,externalUserId:s.externalUserId?.trim()||null,email:(0,C.normalizeAuthEmail)(s.email)});return[...new Set(y.map(I=>I.groupId))].sort((I,D)=>I-D)},async isEmailAllowedByGroup(r){if(!u.isEnabled)return!1;let s=(0,C.normalizeAuthEmail)(r);if(s==="")return!1;await l();let[y]=await i.select({id:h.id}).from(h).innerJoin(p,(0,d.eq)(p.groupId,h.groupId)).innerJoin(a,(0,d.and)((0,d.eq)(a.id,h.groupId),(0,d.eq)(a.isActive,!0))).where((0,d.eq)(h.email,s));return!!y},async listAllowlistGroups(r){return(0,x.assertTenantId)(r,"listAllowlistGroups(tenantId)"),await l(),(await i.select({id:p.id,groupId:p.groupId,groupKey:a.groupKey,groupName:a.name,description:p.description}).from(p).innerJoin(a,(0,d.and)((0,d.eq)(a.id,p.groupId),(0,d.eq)(a.tenantId,r))).where((0,d.eq)(p.tenantId,r)).orderBy((0,d.asc)(a.name))).map(y=>({id:Number(y.id),type:"group",groupId:Number(y.groupId),groupKey:String(y.groupKey),groupName:String(y.groupName),...y.description?{description:String(y.description)}:{},owner:{kind:"tenant",tenantId:r},readOnly:!1}))},async addAllowlistGroup(r,s,y,I){(0,x.assertTenantId)(r,"addAllowlistGroup(tenantId)"),await l(),await i.transaction(async D=>{await T(D,r,s);let[k]=await D.select({id:o.id}).from(o).where((0,d.and)((0,d.eq)(o.groupId,s),(0,d.eq)(o.tenantId,r)));if(!k)throw new Error(`Group ${s} is locally managed; only externally-sourced groups can gate sign-in, because the decision reads the upstream member ledger.`);await D.insert(p).output().values({tenantId:r,groupId:s,description:y??null,createdAt:new Date,createdBy:I})})},async removeAllowlistGroup(r,s){(0,x.assertTenantId)(r,"removeAllowlistGroup(tenantId)"),await l(),await i.delete(p).where((0,d.and)((0,d.eq)(p.id,s),(0,d.eq)(p.tenantId,r)))},async countProjectedMembers(r,s){(0,x.assertTenantId)(r,"countProjectedMembers(tenantId)"),await l();let[y]=await i.select({n:(0,d.count)()}).from(v).innerJoin(a,(0,d.and)((0,d.eq)(a.id,v.groupId),(0,d.eq)(a.tenantId,r))).where((0,d.eq)(v.groupId,s));return Number(y?.n??0)}}}var ae=require("@aiquants/auth-core"),j=require("@aiquants/authz-core");async function Ae(t,n){let g=(0,j.assertTenantId)(n.tenantId,"promoteLedgerForUser(tenantId)");if(!Number.isInteger(n.userId)||n.userId<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] userId must be a positive integer, received ${String(n.userId)}`);let u=(0,ae.normalizeAuthEmail)(n.email),i=n.externalUserId?.trim()||null;if(i===null&&u==="")return{addedGroupIds:[],matchedLedgerIds:[]};let l=await t.findLedgerMatches({tenantId:g,externalUserId:i,email:u});if(l.length===0)return{addedGroupIds:[],matchedLedgerIds:[]};for(let o of l)(0,j.assertTenantMatch)(g,o.tenantId,"promoteLedgerForUser(findLedgerMatches row)");let c=[...new Set(l.map(o=>o.ledgerId))].sort((o,h)=>o-h),b=[...new Set(l.map(o=>o.groupId))].sort((o,h)=>o-h);return{addedGroupIds:[...await t.attachUserToGroups({tenantId:g,userId:n.userId,ledgerIds:c,groupIds:b})].sort((o,h)=>o-h),matchedLedgerIds:c}}var Q=require("@aiquants/authz-core"),M=require("drizzle-orm");var de=2100;var Be=500;function L(t,n=500){if(!Number.isInteger(n)||n<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] chunk size must be a positive integer, received ${String(n)}`);let g=[];for(let u=0;u<t.length;u+=n)g.push(t.slice(u,u+n));return g}function N(t,n,g=100){if(!Number.isInteger(n)||n<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] parametersPerItem must be a positive integer, received ${String(n)}`);if(!Number.isInteger(g)||g<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] reservedParameters must be a non-negative integer, received ${String(g)}`);let u=2100-g,i=Math.floor(u/n);if(i<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] a single item binds ${n} parameters, which exceeds the ${u} available in one statement`);return L(t,i)}var ve=4,Te=100;function De(t,n,g,u){let i=t,l=u.ensureConnection??(async()=>{}),c=u.now??(()=>new Date),b=n.TDGroupMemberEmail,{TMGroup:f,TDGroupMember:o}=g;return{async findLedgerMatches(h){return(0,Q.assertTenantId)(h.tenantId,"findLedgerMatches(tenantId)"),await l(),q(i,{ledger:b,group:f},h)},async attachUserToGroups({tenantId:h,userId:e,ledgerIds:p,groupIds:w}){return(0,Q.assertTenantId)(h,"attachUserToGroups(tenantId)"),await l(),p.length===0?[]:i.transaction(async a=>{let v=new Set;for(let r of L(w)){let s=await a.select({id:f.id}).from(f).where((0,M.and)((0,M.inArray)(f.id,r),(0,M.eq)(f.tenantId,h),(0,M.eq)(f.isActive,!0)));for(let y of s)v.add(Number(y.id))}let S=w.filter(r=>v.has(r));if(S.length===0)return[];let T=new Set;for(let r of L(S)){let s=await a.select({groupId:o.groupId}).from(o).where((0,M.and)((0,M.eq)(o.userId,e),(0,M.inArray)(o.groupId,r)));for(let y of s)T.add(Number(y.groupId))}let G=S.filter(r=>!T.has(r)),_=Math.max(1,2100-Te-S.length);for(let r of L(p,_))await a.update(b).set({resolvedUserId:e}).output().where((0,M.and)((0,M.inArray)(b.id,r),(0,M.inArray)(b.groupId,S)));if(G.length>0){let r=c();for(let s of N(G,ve))await a.insert(o).output().values(s.map(y=>({groupId:y,userId:e,createdAt:r,createdBy:u.actor})))}return G})}}}var U=require("@aiquants/authz-drizzle"),m=require("drizzle-orm/mssql-core"),ue="provider",xe=["TDGroupExternalLink","TDTenantMembershipGroup","TDAllowlistGroup","TDDirectorySyncRequest","TMAllowlist"];function ke(t,n){let g=(0,m.mssqlSchema)(t),u=()=>({createdAt:(0,m.datetime2)("created_at"),createdBy:(0,m.nvarchar)("created_by",{length:50}),updatedAt:(0,m.datetime2)("updated_at"),updatedBy:(0,m.nvarchar)("updated_by",{length:50})}),i=()=>({createdAt:(0,m.datetime2)("created_at"),createdBy:(0,m.nvarchar)("created_by",{length:50})}),l=g.table("TDGroupExternalLink",{id:(0,m.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,m.bigint)("group_id",{mode:"number"}).notNull(),tenantId:(0,m.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),provider:(0,m.nvarchar)(ue,{length:32}).notNull(),externalId:(0,m.nvarchar)("external_id",{length:256}).notNull(),externalKey:(0,m.nvarchar)("external_key",{length:320}).notNull(),membershipMode:(0,m.nvarchar)("membership_mode",{length:16}).notNull(),isSyncEnabled:(0,m.bit)("is_sync_enabled").notNull(),syncedAt:(0,m.datetime2)("synced_at"),syncError:(0,m.nvarchar)("sync_error",{length:1e3}),vanishedObservations:(0,m.int)("vanished_observations").notNull(),...u()},e=>[(0,m.primaryKey)({name:`${t}_TDGroupExternalLink_pk`,columns:[e.id]}),(0,m.uniqueIndex)(`${t}_TDGroupExternalLink_group_uq`).on(e.groupId),(0,m.uniqueIndex)(`${t}_TDGroupExternalLink_external_uq`).on(e.tenantId,e.provider,e.externalId),(0,m.foreignKey)({name:`${t}_TDGroupExternalLink_group_id_fk`,columns:[e.groupId],foreignColumns:[n.groupTable.id]})]),c=g.table("TDGroupMemberEmail",{id:(0,m.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,m.bigint)("group_id",{mode:"number"}).notNull(),email:(0,m.nvarchar)("email",{length:320}).notNull(),externalUserId:(0,m.nvarchar)("external_user_id",{length:128}),resolvedUserId:(0,m.bigint)("resolved_user_id",{mode:"number"}),observedAt:(0,m.datetime2)("observed_at").notNull(),...u()},e=>[(0,m.primaryKey)({name:`${t}_TDGroupMemberEmail_pk`,columns:[e.id]}),(0,m.uniqueIndex)(`${t}_TDGroupMemberEmail_group_email_uq`).on(e.groupId,e.email),(0,m.foreignKey)({name:`${t}_TDGroupMemberEmail_group_id_fk`,columns:[e.groupId],foreignColumns:[n.groupTable.id]})]),b=g.table("TDTenantMembershipGroup",{tenantId:(0,m.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,m.bigint)("group_id",{mode:"number"}).notNull(),isBreakGlass:(0,m.bit)("is_break_glass").notNull(),...i()},e=>[(0,m.primaryKey)({name:`${t}_TDTenantMembershipGroup_pk`,columns:[e.tenantId,e.groupId]}),(0,m.foreignKey)({name:`${t}_TDTenantMembershipGroup_group_id_fk`,columns:[e.groupId],foreignColumns:[n.groupTable.id]})]),f=g.table("TDAllowlistGroup",{id:(0,m.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,m.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,m.bigint)("group_id",{mode:"number"}).notNull(),description:(0,m.nvarchar)("description",{length:512}),...i()},e=>[(0,m.primaryKey)({name:`${t}_TDAllowlistGroup_pk`,columns:[e.id]}),(0,m.uniqueIndex)(`${t}_TDAllowlistGroup_tenant_group_uq`).on(e.tenantId,e.groupId),(0,m.foreignKey)({name:`${t}_TDAllowlistGroup_group_id_fk`,columns:[e.groupId],foreignColumns:[n.groupTable.id]})]),o=g.table("TDDirectorySyncRequest",{id:(0,m.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,m.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,m.bigint)("group_id",{mode:"number"}),requestedBy:(0,m.nvarchar)("requested_by",{length:320}).notNull(),requestedAt:(0,m.datetime2)("requested_at").notNull(),pickedAt:(0,m.datetime2)("picked_at"),finishedAt:(0,m.datetime2)("finished_at"),result:(0,m.nvarchar)("result",{length:32}),error:(0,m.nvarchar)("error",{length:2e3}),...i()},e=>[(0,m.primaryKey)({name:`${t}_TDDirectorySyncRequest_pk`,columns:[e.id]})]),h=g.table("TMAllowlist",{id:(0,m.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,m.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),pattern:(0,m.nvarchar)("pattern",{length:256}).notNull(),type:(0,m.nvarchar)("type",{length:32}).notNull(),description:(0,m.nvarchar)("description",{length:512}),...i()},e=>[(0,m.primaryKey)({name:`${t}_TMAllowlist_pk`,columns:[e.id]}),(0,m.uniqueIndex)(`${t}_TMAllowlist_pattern_uq`).on(e.tenantId,e.pattern)]);return{TDGroupExternalLink:l,TDGroupMemberEmail:c,TDTenantMembershipGroup:b,TDAllowlistGroup:f,TDDirectorySyncRequest:o,TMAllowlist:h}}var F=require("@aiquants/auth-directory-core");var Z=(t,n=20)=>t.length<=n?t.join(", "):`${t.slice(0,n).join(", ")} \u307B\u304B ${t.length-n} \u4EF6`,ee={upstreamUnreadable:t=>`\u4E0A\u6D41\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8AAD\u307F\u53D6\u308A\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${t}`,localWriteFailed:t=>`\u30ED\u30FC\u30AB\u30EB\u3078\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${t}`,resolverIncomplete:(t,n)=>`\u4E0A\u6D41\u304C ${t} \u4EF6\u306E\u30E1\u30F3\u30D0\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F\u304C\u3001\u7A81\u5408\u7D50\u679C\u306F ${n} \u4EF6\u3067\u3057\u305F\u3002\u4EF6\u6570\u304C\u6E1B\u308B\u7A81\u5408\u306F\u3001\u89E3\u6C7A\u3067\u304D\u306A\u304B\u3063\u305F\u4EBA\u7269\u3092\u300C\u4E0A\u6D41\u304B\u3089\u6D88\u3048\u305F\u300D\u3068\u3057\u3066\u524A\u9664\u3057\u3066\u3057\u307E\u3046\u305F\u3081\u4E2D\u65AD\u3057\u307E\u3057\u305F\u3002\u89E3\u6C7A\u3067\u304D\u306A\u3044\u30E1\u30F3\u30D0\u30FC\u306F\u7701\u7565\u305B\u305A resolvedUserId: null \u3067\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002`,groupMissing:(t,n,g)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${t})\u3002\u9023\u7D9A ${n} \u56DE\u76EE\u3067\u3059\u3002${g} \u56DE\u306B\u9054\u3057\u305F\u6642\u70B9\u3067\u30B0\u30EB\u30FC\u30D7\u3092\u7121\u52B9\u5316\u3057\u307E\u3059\u3002`,groupVanished:(t,n)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C ${n} \u56DE\u9023\u7D9A\u3067\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F (${t})\u3002\u30B0\u30EB\u30FC\u30D7\u3092\u7121\u52B9\u5316\u3057\u307E\u3057\u305F\u3002\u4E0A\u6D41\u304C\u5FA9\u65E7\u3059\u308C\u3070\u6B21\u56DE\u306E\u540C\u671F\u3067\u81EA\u52D5\u7684\u306B\u518D\u6709\u52B9\u5316\u3055\u308C\u307E\u3059\u3002`,planRefused:t=>{if(t.reason==="invalid-upstream-data")return`\u540C\u671F\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F: \u4E0A\u6D41\u306E\u30E1\u30F3\u30D0\u30FC\u4E00\u89A7\u306B\u6271\u3048\u306A\u3044\u30A2\u30C9\u30EC\u30B9\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 (${Z(t.offendingEmails)})\u3002`;let n=t.axis==="membership"?"\u6A29\u9650\u3092\u5931\u3046\u4EBA\u6570":"\u30B5\u30A4\u30F3\u30A4\u30F3\u3067\u304D\u306A\u304F\u306A\u308B\u4EBA\u6570",g=t.axis==="membership"?t.withheldProjectionRemoves.map(String):t.withheldLedgerDeletes;return[`\u540C\u671F\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F: ${n}\u304C ${t.population} \u4EBA\u4E2D ${t.removalCount} \u4EBA\u306B\u306A\u308A\u307E\u3059`,`(\u4E0A\u9650: ${t.limits.maxRemovalCount} \u4EF6 / \u6BD4\u7387 ${t.limits.maxRemovalRatio})\u3002`,`\u5DEE\u3057\u6B62\u3081\u305F\u5BFE\u8C61: ${Z(g)}\u3002`,"\u4E0A\u6D41\u5074\u306E\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u610F\u56F3\u3057\u305F\u5909\u66F4\u3067\u3042\u308C\u3070\u3001\u3053\u306E\u8EF8\u306E\u4E0A\u9650\u3060\u3051\u3092\u4E00\u6642\u7684\u306B\u5F15\u304D\u4E0A\u3052\u3066\u518D\u5B9F\u884C\u3057\u307E\u3059\u3002"].join(" ")},removalsRefused:t=>`${t.length} \u4EF6\u306E\u6240\u5C5E\u89E3\u9664\u304C\u6700\u5F8C\u306E\u7BA1\u7406\u8005\u30AC\u30FC\u30C9\u306B\u3088\u308A\u62D2\u5426\u3055\u308C\u307E\u3057\u305F (\u30E6\u30FC\u30B6\u30FC ${Z(t.map(n=>String(n.userId)))})\u3002\u6B8B\u308A\u306E\u5909\u66F4\u306F\u9069\u7528\u6E08\u307F\u3067\u3059\u3002`,foreignProvider:(t,n)=>`\u3053\u306E\u30EA\u30F3\u30AF\u306E\u4F9B\u7D66\u5143\u306F ${t} \u3067\u3059\u304C\u3001\u5B9F\u884C\u4E2D\u306E\u540C\u671F\u306F ${n} \u7528\u3067\u3059\u3002\u5BFE\u5FDC\u3059\u308B\u540C\u671F\u30B8\u30E7\u30D6\u304B\u3089\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002`};var re=["aborted","missing","vanished","upstream-failed","local-failed","foreign-provider"];function Ge(t){let{directory:n,repository:g,policy:u,now:i,logger:l}=t,c=t.messages??ee;if((0,F.assertBlastRadiusPolicy)(u),!Number.isInteger(t.vanishedThreshold)||t.vanishedThreshold<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] vanishedThreshold must be a positive integer, received ${String(t.vanishedThreshold)}`);if(typeof t.provider!="string"||t.provider.trim()==="")throw new TypeError("[@aiquants/auth-directory-drizzle] provider must be a non-empty string so links of other providers can be told apart");async function b(e,p){try{await g.recordFailure(e,p)}catch(w){l.error(`[auth-directory] could not record the failure for ${e.externalKey}:`,w)}}async function f(e){try{let p=await n.getGroup(e.externalId);return p===null?{kind:"missing"}:{kind:"ok",group:p,members:await n.listGroupMembers(p,e.membershipMode)}}catch(p){return{kind:"failed",error:p instanceof Error?p:new Error(String(p))}}}async function o(e){let p=await g.recordVanishedObservation(e,c.groupMissing(e.externalKey,e.vanishedObservations+1,t.vanishedThreshold));return p<t.vanishedThreshold?(l.warn(`[auth-directory] ${e.externalKey} missing upstream (${p}/${t.vanishedThreshold})`),{kind:"missing",link:e,observations:p}):(await g.markGroupInactive(e),await b(e,c.groupVanished(e.externalKey,p)),l.warn(`[auth-directory] ${e.externalKey} deactivated after ${p} consecutive absences`),{kind:"vanished",link:e})}async function h(e){if(e.provider!==t.provider)return await b(e,c.foreignProvider(e.provider,t.provider)),l.warn(`[auth-directory] skipping ${e.externalKey}: belongs to provider ${e.provider}`),{kind:"foreign-provider",link:e};let p=await f(e);if(p.kind==="missing")return o(e);if(p.kind==="failed")return await b(e,c.upstreamUnreadable(p.error.message)),l.error(`[auth-directory] upstream read failed for ${e.externalKey}:`,p.error),{kind:"upstream-failed",link:e,error:p.error};try{let[w,a]=await Promise.all([g.loadGroupSnapshot(e),g.resolveMembers(p.members)]);if(a.length!==p.members.length){let _=c.resolverIncomplete(p.members.length,a.length);return await b(e,_),l.error(`[auth-directory] ${_}`),{kind:"local-failed",link:e,error:new Error(_)}}let v=(0,F.reconcile)(w,a,u);if(v.aborted)return await b(e,c.planRefused(v.aborted)),l.warn(`[auth-directory] plan refused for ${e.externalKey}: ${v.aborted.reason}`),{kind:"aborted",link:e,plan:v};let S=v.ledgerUpserts.length>0||v.ledgerDeletes.length>0||v.projectionAdds.length>0||v.projectionRemoves.length>0,T=i(),G={refusals:[]};return S&&(G=await g.applyPlan(e,v,T)),await g.recordSuccess(e,p.group,T),G.refusals.length>0&&(await b(e,c.removalsRefused(G.refusals)),l.warn(`[auth-directory] ${G.refusals.length} removal(s) refused for ${e.externalKey}`)),v.unresolvedEmails.length>0&&l.info(`[auth-directory] ${e.externalKey}: ${v.unresolvedEmails.length} upstream member(s) have no local user yet`),S?{kind:"applied",link:e,plan:v}:{kind:"unchanged",link:e}}catch(w){let a=w instanceof Error?w:new Error(String(w));return await b(e,c.localWriteFailed(a.message)),l.error(`[auth-directory] local write failed for ${e.externalKey}:`,a),{kind:"local-failed",link:e,error:a}}}return{syncOne:h,async run(e={}){let p=await g.listSyncableLinks(e),w=[];for(let v of p)try{w.push(await h(v))}catch(S){let T=S instanceof Error?S:new Error(String(S));l.error(`[auth-directory] ${v.externalKey} ended abnormally:`,T),w.push({kind:"local-failed",link:v,error:T})}let a=w.filter(v=>re.includes(v.kind)).length;return l.info(`[auth-directory] run finished: ${w.length} link(s), ${a} unhealthy`),{outcomes:w,unhealthyCount:a}}}}var le=require("@aiquants/authz-core"),P=require("drizzle-orm"),te=2e3;function Re(t,n,g){let u=t,i=g.ensureConnection??(async()=>{}),l=n.TDDirectorySyncRequest,c=g.maxErrorLength??te;if(!Number.isInteger(c)||c<1||c>te)throw new TypeError(`[@aiquants/auth-directory-drizzle] maxErrorLength must be an integer within 1..${te}, received ${String(g.maxErrorLength)}`);return{async claim(){await i();let b=await u.select({id:l.id}).from(l).where((0,P.isNull)(l.pickedAt)).orderBy((0,P.asc)(l.id));for(let f of b){let h=(await u.update(l).set({pickedAt:g.now()}).output().where((0,P.and)((0,P.eq)(l.id,Number(f.id)),(0,P.isNull)(l.pickedAt))))?.[0];if(!h)continue;let e=String(h.tenant_id??h.tenantId??""),p=h.group_id??h.groupId??null;return{id:Number(h.id),tenantId:(0,le.assertTenantId)(e,"claim(row.tenantId)"),groupId:p===null?null:Number(p),requestedBy:String(h.requested_by??h.requestedBy??"")}}return null},async finish(b,f){await i();let o=f.error?f.error.slice(0,c):null;await u.update(l).set({finishedAt:g.now(),result:f.result,error:o}).output().where((0,P.eq)(l.id,b))},async listStranded(b){return await i(),(await u.select({id:l.id,pickedAt:l.pickedAt}).from(l).where((0,P.isNull)(l.finishedAt)).orderBy((0,P.asc)(l.id))).filter(o=>o.pickedAt!==null&&new Date(o.pickedAt)<b).map(o=>Number(o.id))}}}var ne=require("@aiquants/auth-core"),O=require("@aiquants/authz-core"),A=require("drizzle-orm");var Ee=7,Me=4;function Pe(t,n,g,u){let i=t,l=u.ensureConnection??(async()=>{}),{TDGroupExternalLink:c,TDGroupMemberEmail:b}=n,{TMGroup:f,TDGroupMember:o}=g,h=u.actor;return{async listSyncableLinks(e){await l();let p=[(0,A.eq)(c.isSyncEnabled,!0)];return e.tenantId!==void 0&&p.push((0,A.eq)(c.tenantId,(0,O.assertTenantId)(e.tenantId,"listSyncableLinks(tenantId)"))),e.groupId!==void 0&&p.push((0,A.eq)(c.groupId,e.groupId)),(await i.select({linkId:c.id,groupId:c.groupId,linkTenantId:c.tenantId,groupTenantId:f.tenantId,groupKey:f.groupKey,isGroupActive:f.isActive,provider:c.provider,externalId:c.externalId,externalKey:c.externalKey,membershipMode:c.membershipMode,vanishedObservations:c.vanishedObservations}).from(c).innerJoin(f,(0,A.eq)(f.id,c.groupId)).where((0,A.and)(...p))).map(a=>((0,O.assertTenantMatch)(String(a.groupTenantId),String(a.linkTenantId),"listSyncableLinks(link.tenantId vs TMGroup.tenant_id)"),{linkId:Number(a.linkId),groupId:Number(a.groupId),groupKey:String(a.groupKey),tenantId:String(a.groupTenantId),provider:String(a.provider),externalId:String(a.externalId),externalKey:String(a.externalKey),membershipMode:K(String(a.membershipMode)),isGroupActive:!!a.isGroupActive,vanishedObservations:Number(a.vanishedObservations??0)}))},async loadGroupSnapshot(e){await l();let[p,w]=await Promise.all([i.select({email:b.email,externalUserId:b.externalUserId,resolvedUserId:b.resolvedUserId}).from(b).where((0,A.eq)(b.groupId,e.groupId)),i.select({userId:o.userId}).from(o).where((0,A.eq)(o.groupId,e.groupId))]);return{ledger:p.map(a=>({email:String(a.email),...a.externalUserId?{externalUserId:String(a.externalUserId)}:{},resolvedUserId:a.resolvedUserId===null?null:Number(a.resolvedUserId)})),projectedUserIds:w.map(a=>Number(a.userId))}},resolveMembers(e){return u.memberResolver.resolve(e)},async applyPlan(e,p,w){(0,O.assertTenantId)(e.tenantId,"applyPlan(link.tenantId)"),await l(),(p.ledgerUpserts.length>0||p.projectionAdds.length>0)&&await i.transaction(async S=>{let T=p.ledgerUpserts.map(r=>({...r,email:(0,ne.normalizeAuthEmail)(r.email)})),G=new Map;for(let r of L(T.map(s=>s.email))){let s=await S.select({id:b.id,email:b.email}).from(b).where((0,A.and)((0,A.eq)(b.groupId,e.groupId),(0,A.inArray)(b.email,r)));for(let y of s)G.set(String(y.email),Number(y.id))}let _=T.filter(r=>!G.has(r.email));for(let r of N(_,Ee))await S.insert(b).output().values(r.map(s=>({groupId:e.groupId,email:s.email,externalUserId:s.externalUserId??null,resolvedUserId:s.resolvedUserId,observedAt:w,createdAt:w,createdBy:h})));for(let r of T){let s=G.get(r.email);s!==void 0&&await S.update(b).set({externalUserId:r.externalUserId??null,resolvedUserId:r.resolvedUserId,observedAt:w,updatedAt:w,updatedBy:h}).output().where((0,A.eq)(b.id,s))}for(let r of N(p.projectionAdds,Me)){let s=new Set((await S.select({userId:o.userId}).from(o).where((0,A.and)((0,A.eq)(o.groupId,e.groupId),(0,A.inArray)(o.userId,r)))).map(I=>Number(I.userId))),y=r.filter(I=>!s.has(I));y.length>0&&await S.insert(o).output().values(y.map(I=>({groupId:e.groupId,userId:I,createdAt:w,createdBy:h})))}});let a=[];for(let S of p.projectionRemoves)try{await u.lockoutGuard.guardedWrite(e.tenantId,{removeGroupMembership:{groupId:e.groupId,userId:S}},"remove-group-member",T=>T.delete(o).where((0,A.and)((0,A.eq)(o.groupId,e.groupId),(0,A.eq)(o.userId,S))))}catch(T){a.push({userId:S,applied:!1,refusal:T instanceof Error?T.message:String(T)})}let v=a.map(S=>S.userId);return p.ledgerDeletes.length>0&&await i.transaction(async S=>{for(let T of L(p.ledgerDeletes)){let G=v.length>0?(0,A.or)((0,A.isNull)(b.resolvedUserId),(0,A.notInArray)(b.resolvedUserId,v)):void 0;await S.delete(b).where((0,A.and)((0,A.eq)(b.groupId,e.groupId),(0,A.inArray)(b.email,T),...G?[G]:[]))}}),{refusals:a}},async recordSuccess(e,p,w){await l(),await i.transaction(async a=>{await a.update(c).set({syncedAt:w,syncError:null,vanishedObservations:0,externalId:p.externalId,externalKey:(0,ne.normalizeAuthEmail)(p.externalKey),updatedAt:w,updatedBy:h}).output().where((0,A.eq)(c.id,e.linkId)),e.isGroupActive||await a.update(f).set({isActive:!0,updatedAt:w,updatedBy:h}).output().where((0,A.and)((0,A.eq)(f.id,e.groupId),(0,A.eq)(f.tenantId,e.tenantId)))})},async recordFailure(e,p){await l(),await i.update(c).set({syncError:p.slice(0,1e3),updatedAt:new Date,updatedBy:h}).output().where((0,A.eq)(c.id,e.linkId))},async recordVanishedObservation(e,p){await l();let w=e.vanishedObservations+1;return await i.update(c).set({vanishedObservations:w,syncError:p.slice(0,1e3),updatedAt:new Date,updatedBy:h}).output().where((0,A.eq)(c.id,e.linkId)),w},async markGroupInactive(e){await l(),await i.update(f).set({isActive:!1,updatedAt:new Date,updatedBy:h}).output().where((0,A.and)((0,A.eq)(f.id,e.groupId),(0,A.eq)(f.tenantId,e.tenantId)))}}}0&&(module.exports={AUTH_DIRECTORY_PROVIDER_COLUMN,AUTH_DIRECTORY_TENANT_SCOPED_TABLES,MAX_IN_LIST,MAX_PARAMETERS,MEMBERSHIP_MODES,UNHEALTHY_SYNC_OUTCOMES,assertGroupMayBeLinked,assertMembershipMode,chunk,chunkByParameters,createDirectoryLinkStore,createDirectorySync,createDirectorySyncRepository,createPromotionRepository,createSyncRequestQueue,defaultExternalGroupGuardMessage,defaultSyncMessages,defineAuthDirectorySchema,findLedgerRowsForIdentity,promoteLedgerForUser,withExternalGroupGuards});
|
|
1
|
+
"use strict";var ie=Object.defineProperty;var Te=Object.getOwnPropertyDescriptor;var De=Object.getOwnPropertyNames;var xe=Object.prototype.hasOwnProperty;var ke=(e,t)=>{for(var m in t)ie(e,m,{get:t[m],enumerable:!0})},Ee=(e,t,m,d)=>{if(t&&typeof t=="object"||typeof t=="function")for(let u of De(t))!xe.call(e,u)&&u!==m&&ie(e,u,{get:()=>t[u],enumerable:!(d=Te(t,u))||d.enumerable});return e};var Re=e=>Ee(ie({},"__esModule",{value:!0}),e);var Xe={};ke(Xe,{AUTH_DIRECTORY_PROVIDER_COLUMN:()=>te,AUTH_DIRECTORY_TENANT_SCOPED_TABLES:()=>Be,MAX_IN_LIST:()=>ye,MAX_PARAMETERS:()=>Y,MEMBERSHIP_MODES:()=>se,NEWLY_UNHEALTHY_SYNC_OUTCOMES:()=>ne,RESERVED_PARAMETERS:()=>me,STRANDED_REASON:()=>ve,UNHEALTHY_SYNC_OUTCOMES:()=>ce,assertGroupMayBeLinked:()=>$e,assertMembershipMode:()=>z,chunk:()=>L,chunkByParameters:()=>N,classifySyncFailure:()=>W,createDirectoryCatalogReader:()=>_e,createDirectoryCatalogWriter:()=>Ce,createDirectoryLinkStore:()=>Ne,createDirectorySync:()=>je,createDirectorySyncRepository:()=>Ye,createPromotionRepository:()=>ze,createSyncRequestQueue:()=>We,defaultExternalGroupGuardMessage:()=>Pe,defaultSyncMessages:()=>le,defineAuthDirectorySchema:()=>Fe,findLedgerRowsForIdentity:()=>j,promoteLedgerForUser:()=>qe,toInstant:()=>K,withExternalGroupGuards:()=>Le});module.exports=Re(Xe);var ae=require("@aiquants/authz-core"),_=require("drizzle-orm");function K(e){return e instanceof Date?e:new Date(/(?:Z|[+-]\d{2}:?\d{2})$/.test(e)?e:`${e.replace(" ","T")}Z`)}var Y=2100,me=100,ye=500;function L(e,t=500){if(!Number.isInteger(t)||t<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] chunk size must be a positive integer, received ${String(t)}`);let m=[];for(let d=0;d<e.length;d+=t)m.push(e.slice(d,d+t));return m}function N(e,t,m=100){if(!Number.isInteger(t)||t<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] parametersPerItem must be a positive integer, received ${String(t)}`);if(!Number.isInteger(m)||m<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] reservedParameters must be a non-negative integer, received ${String(m)}`);let d=2100-m,u=Math.floor(d/t);if(u<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] a single item binds ${t} parameters, which exceeds the ${d} available in one statement`);return L(e,u)}var Me=10,$={tenantId:64,provider:32,externalId:256,externalKey:320,name:256,description:1e3,actor:50},ge=2147483647;function Ge(e){if(e===void 0||!Number.isFinite(e))return null;let t=Math.trunc(e);return t<0?null:t>ge?ge:t}function B(e,t,m){let d=e.trim();if(d==="")throw new TypeError(`[@aiquants/auth-directory-drizzle] ${m} must not be blank`);if(d.length>t)throw new TypeError(`[@aiquants/auth-directory-drizzle] ${m} exceeds its column length (${t}); truncating it would change which rows it owns`);return d}function Ce(e,t,m){let d=e,u=m.ensureConnection??(async()=>{}),s=t.TDDirectoryCatalog,b=t.TMDirectoryCatalogObservation,f=S=>{let a=new Map;for(let g of S)a.set(g.externalId,g);return[...a.values()]};return{async replace(S,a,g){await u();let r=B((0,ae.assertTenantId)(S,"replace(tenantId)"),$.tenantId,"tenantId"),n=B(a,$.provider,"provider"),i=B(m.actor,$.actor,"actor"),l=m.now(),I=f(g.map(w=>({tenantId:r,provider:n,externalId:w.externalId.slice(0,$.externalId),externalKey:w.externalKey.slice(0,$.externalKey),name:w.name.slice(0,$.name),description:w.description===void 0?null:w.description.slice(0,$.description),memberCount:Ge(w.memberCount),observedAt:l,createdAt:l,createdBy:i})));return await d.transaction(async w=>{await w.delete(s).where((0,_.and)((0,_.eq)(s.tenantId,r),(0,_.eq)(s.provider,n)));for(let E of N(I,Me))await w.insert(s).values(E);await w.delete(b).where((0,_.and)((0,_.eq)(b.tenantId,r),(0,_.eq)(b.provider,n))),await w.insert(b).values([{tenantId:r,provider:n,observedAt:l,entryCount:I.length,createdAt:l,createdBy:i,updatedAt:l,updatedBy:i}])}),I.length}}}function _e(e,t,m={}){let d=e,u=m.ensureConnection??(async()=>{}),s=t.TDDirectoryCatalog,b=t.TMDirectoryCatalogObservation;return{async read(f,S){await u();let a=B((0,ae.assertTenantId)(f,"read(tenantId)"),$.tenantId,"tenantId"),g=B(S,$.provider,"provider"),r=await d.select({observedAt:b.observedAt,entryCount:b.entryCount,externalId:s.externalId,externalKey:s.externalKey,name:s.name,description:s.description,memberCount:s.memberCount}).from(b).leftJoin(s,(0,_.and)((0,_.eq)(s.tenantId,b.tenantId),(0,_.eq)(s.provider,b.provider))).where((0,_.and)((0,_.eq)(b.tenantId,a),(0,_.eq)(b.provider,g))).orderBy((0,_.asc)(s.name)),n=r.filter(I=>I.externalId!==null).map(I=>({externalId:String(I.externalId),externalKey:String(I.externalKey),name:String(I.name),...I.description===null?{}:{description:I.description},...I.memberCount===null?{}:{memberCount:Number(I.memberCount)}})),i=r[0];if(i===void 0)return{groups:n,observedAt:null};if(Number(i.entryCount)!==n.length)throw new Error(`[@aiquants/auth-directory-drizzle] catalog is inconsistent for (${a}, ${g}): the observation records ${i.entryCount} entries but ${n.length} rows are present`);let l=K(i.observedAt);if(!Number.isFinite(l.getTime()))throw new Error(`[@aiquants/auth-directory-drizzle] catalog observation for (${a}, ${g}) has an unreadable observed_at`);return{groups:n,observedAt:l}}}}var he=require("@aiquants/authz-core"),Pe=(e,t)=>`\u5916\u90E8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u9023\u643A\u30B0\u30EB\u30FC\u30D7 (${t}) \u306B\u306F\u7BA1\u7406\u30ED\u30FC\u30EB (${e}) \u3092\u6301\u305F\u305B\u3089\u308C\u307E\u305B\u3093\u3002\u4E0A\u6D41\u5074\u306E\u6240\u5C5E\u5909\u66F4\u304C\u305D\u306E\u307E\u307E\u7BA1\u7406\u8005\u306E\u5897\u6E1B\u306B\u306A\u308B\u305F\u3081\u3001\u7BA1\u7406\u8005\u7D4C\u8DEF\u306F\u30ED\u30FC\u30AB\u30EB\u7BA1\u7406\u306E\u30B0\u30EB\u30FC\u30D7\u306B\u9650\u5B9A\u3057\u3066\u3044\u307E\u3059\u3002`;function U(e,t,m,d){return new Set(e.filter(u=>t.has(u.roleId)&&u.appKey===m&&u.resourceKey===d).map(u=>u.action))}function X(e,t){return new Set(e.filter(m=>m.groupId===t).map(m=>m.roleId))}var F=e=>he.AUTHZ_ACTIONS.every(t=>e.has(t)),Z=(e,t)=>e.find(m=>m.roleId===t)?.roleKey??`#${t}`;function Q(e,t,m,d){let u=[...t].find(b=>F(U(e,new Set([b]),m,d)));return u!==void 0?Z(e,u):[...t].filter(b=>U(e,new Set([b]),m,d).size>0).map(b=>Z(e,b)).join(" + ")}function Le(e,t){return be(e,t)}function be(e,t){let m=e;return{...e,withTransaction:(d,u)=>m.withTransaction((s,b)=>d(be(s,t),b),u),async assignGroupRole(d,u,s,b){await m.withTransaction(async(f,S)=>{let a=await f.listGrants(d),g=X(await f.listGroupRoles(d),u);if(g.add(s),F(U(a,g,t.adminAppKey,t.adminResourceKey))){let r=await t.linkLookup.externalGroupKey(d,u,S);if(r!==null)throw new Error(t.message(Q(a,g,t.adminAppKey,t.adminResourceKey),r))}await f.assignGroupRole(d,u,s,b)})},async updateGrant(d,u,s,b){let f=s.action;if(f===void 0)return m.updateGrant(d,u,s,b);await m.withTransaction(async(S,a)=>{let g=await S.listGrants(d),r=g.find(l=>l.id===u);if(r===void 0)return S.updateGrant(d,u,s,b);let i=(await S.listResources(d)).find(l=>l.id===r.resourceId);if(i?.appKey===t.adminAppKey&&i?.resourceKey===t.adminResourceKey){let l=await S.listGroupRoles(d);for(let I of new Set(l.filter(w=>w.roleId===r.roleId).map(w=>w.groupId))){let w=X(l,I),E=U(g.filter(k=>k.id!==u),w,t.adminAppKey,t.adminResourceKey);if(w.has(r.roleId)&&E.add(f),!F(E))continue;let T=await t.linkLookup.externalGroupKey(d,I,a);if(T!==null)throw new Error(t.message(Q(g,w,t.adminAppKey,t.adminResourceKey)||Z(g,r.roleId),T))}}await S.updateGrant(d,u,s,b)})},async createGrant(d,u,s){await m.withTransaction(async(b,f)=>{let a=(await b.listResources(d)).find(g=>g.id===u.resourceId);if(a?.appKey===t.adminAppKey&&a?.resourceKey===t.adminResourceKey){let g=await b.listGrants(d),r=await b.listGroupRoles(d);for(let n of new Set(r.filter(i=>i.roleId===u.roleId).map(i=>i.groupId))){let i=U(g,X(r,n),t.adminAppKey,t.adminResourceKey);if(i.add(u.action),!F(i))continue;let l=await t.linkLookup.externalGroupKey(d,n,f);if(l!==null)throw new Error(t.message(Q(g,X(r,n),t.adminAppKey,t.adminResourceKey)||Z(g,u.roleId),l))}}await b.createGrant(d,u,s)})}}}async function $e(e,t,m,d){let u=(await e.listGroupRoles(t)).filter(S=>S.groupId===m);if(u.length===0)return;let s=await e.listGrants(t),b=new Set(u.map(S=>S.roleId));if(!F(U(s,b,d.adminAppKey,d.adminResourceKey)))return;let f=u[0];if(f)throw new Error(d.message(Q(s,b,d.adminAppKey,d.adminResourceKey),f.groupKey))}var q=require("drizzle-orm");async function j(e,t,m){let{ledger:d,group:u}=t,{tenantId:s,externalUserId:b,email:f}=m;if(b===null&&f==="")return[];let S={ledgerId:d.id,groupId:d.groupId,tenantId:u.tenantId,externalUserId:d.externalUserId},a=async l=>(await e.select(S).from(d).innerJoin(u,(0,q.and)((0,q.eq)(u.id,d.groupId),(0,q.eq)(u.tenantId,s),(0,q.eq)(u.isActive,!0))).where(l)).map(w=>({ledgerId:Number(w.ledgerId),groupId:Number(w.groupId),tenantId:String(w.tenantId),externalUserId:w.externalUserId===null?null:String(w.externalUserId)})),g=l=>{let I=new Map;for(let w of l)I.set(w.ledgerId,{ledgerId:w.ledgerId,groupId:w.groupId,tenantId:w.tenantId});return[...I.values()].sort((w,E)=>w.ledgerId-E.ledgerId)},r=b===null?[]:await a((0,q.eq)(d.externalUserId,b));if(f==="")return g(r);let n=await a((0,q.eq)(d.email,f)),i=l=>l.externalUserId!==null&&l.externalUserId!==b;return g([...r,...n.filter(l=>!i(l))])}var ee=require("@aiquants/auth-core"),fe=require("@aiquants/auth-directory-core"),G=require("@aiquants/authz-core"),c=require("drizzle-orm");var se=["direct","transitive"];function z(e){if(!se.includes(e))throw new TypeError(`[@aiquants/auth-directory-drizzle] membershipMode must be one of ${se.join(" | ")}, received ${JSON.stringify(e)}`);return e}function Ke(e){let t=typeof e=="object"&&e!==null&&"number"in e?e.number:void 0;return t===2601||t===2627}function Ne(e,t,m,d){let u=e,s=d.ensureConnection??(async()=>{}),b=d.policyCacheTtlMs??0;if(!Number.isFinite(b)||b<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] policyCacheTtlMs must be a non-negative number, received ${String(d.policyCacheTtlMs)}`);let f=new Map,S=o=>f.delete(o),{TDGroupExternalLink:a,TDGroupMemberEmail:g,TDTenantMembershipGroup:r,TDAllowlistGroup:n,TDDirectorySyncRequest:i}=t,{TMGroup:l,TDGroupMember:I}=m;async function w(o,y,h){if((await o.select({groupId:r.groupId}).from(r).where((0,c.and)((0,c.eq)(r.tenantId,y),(0,c.eq)(r.groupId,h),(0,c.eq)(r.isBreakGlass,!0)))).length>0)throw new Error(`Group ${h} is a break-glass proof group; a break-glass proof path must be one the synchronization can never touch.`)}async function E(o,y,h){let[v]=await o.select({id:l.id}).from(l).where((0,c.and)((0,c.eq)(l.id,h),(0,c.eq)(l.tenantId,y)));if(!v)throw new Error(`Group not found in tenant: ${h}`)}function T(o,y){return{linkId:Number(o.linkId),groupId:Number(o.groupId),tenantId:String(o.tenantId),provider:String(o.provider),externalId:String(o.externalId),externalKey:String(o.externalKey),membershipMode:z(String(o.membershipMode)),isSyncEnabled:!!o.isSyncEnabled,...o.syncedAt?{syncedAt:K(o.syncedAt).toISOString()}:{},...o.syncError?{syncError:String(o.syncError)}:{},unresolvedCount:y}}async function k(o,y){let h=await o.select({groupId:g.groupId,n:(0,c.count)()}).from(g).innerJoin(l,(0,c.and)((0,c.eq)(l.id,g.groupId),(0,c.eq)(l.tenantId,y))).where((0,c.isNull)(g.resolvedUserId)).groupBy(g.groupId);return new Map(h.map(v=>[Number(v.groupId),Number(v.n)]))}return{async listLinks(o){(0,G.assertTenantId)(o,"listLinks(tenantId)"),await s();let y=await u.select({linkId:a.id,groupId:a.groupId,tenantId:a.tenantId,provider:a.provider,externalId:a.externalId,externalKey:a.externalKey,membershipMode:a.membershipMode,isSyncEnabled:a.isSyncEnabled,syncedAt:a.syncedAt,syncError:a.syncError}).from(a).where((0,c.eq)(a.tenantId,o)).orderBy((0,c.asc)(a.groupId)),h=await k(u,o);return y.map(v=>((0,G.assertTenantMatch)(o,String(v.tenantId),"listLinks(row.tenantId)"),T(v,h.get(Number(v.groupId))??0)))},async externalGroupKey(o,y,h){(0,G.assertTenantId)(o,"externalGroupKey(tenantId)"),await s();let[v]=await(h??u).select({externalKey:a.externalKey}).from(a).where((0,c.and)((0,c.eq)(a.groupId,y),(0,c.eq)(a.tenantId,o)));return v?String(v.externalKey):null},async linkGroup(o,y,h,v){(0,G.assertTenantId)(o,"linkGroup(tenantId)");let D=z(h.membershipMode),x=h.externalId.trim(),C=(0,ee.normalizeAuthEmail)(h.externalKey);if(x===""||C==="")throw new TypeError("[@aiquants/auth-directory-drizzle] externalId and externalKey must be non-empty");await s(),await d.linkable.assertLinkableAndWrite(o,y,async V=>{let R=V;await E(R,o,y),await w(R,o,y),await R.insert(a).output().values({groupId:y,tenantId:o,provider:h.provider,externalId:x,externalKey:C,membershipMode:D,isSyncEnabled:!0,vanishedObservations:0,createdAt:new Date,createdBy:v})}),S(o)},async unlinkGroup(o,y){(0,G.assertTenantId)(o,"unlinkGroup(tenantId)"),await s(),await u.transaction(async h=>{await E(h,o,y),await h.delete(g).where((0,c.eq)(g.groupId,y)),await h.delete(n).where((0,c.and)((0,c.eq)(n.groupId,y),(0,c.eq)(n.tenantId,o))),await h.delete(a).where((0,c.and)((0,c.eq)(a.groupId,y),(0,c.eq)(a.tenantId,o)))}),S(o)},async setSyncEnabled(o,y,h,v){(0,G.assertTenantId)(o,"setSyncEnabled(tenantId)"),await s(),await u.update(a).set({isSyncEnabled:h,updatedAt:new Date,updatedBy:v}).output().where((0,c.and)((0,c.eq)(a.groupId,y),(0,c.eq)(a.tenantId,o)))},async requestSync(o,y,h){return(0,G.assertTenantId)(o,"requestSync(tenantId)"),await s(),u.transaction(async v=>{if(y!==null&&await E(v,o,y),(await v.select({id:i.id}).from(i).where((0,c.and)((0,c.eq)(i.tenantId,o),y===null?(0,c.isNull)(i.groupId):(0,c.eq)(i.groupId,y),(0,c.isNull)(i.pickedAt)))).length>0)return"already-pending";try{await v.insert(i).output().values({tenantId:o,groupId:y,requestedBy:h,requestedAt:new Date,createdAt:new Date,createdBy:h})}catch(x){if(!Ke(x))throw x;return"already-pending"}return"queued"})},async getStatus(o){(0,G.assertTenantId)(o,"getStatus(tenantId)"),await s();let y=await u.select({groupId:a.groupId,isSyncEnabled:a.isSyncEnabled,syncedAt:a.syncedAt,syncError:a.syncError}).from(a).where((0,c.eq)(a.tenantId,o)),[h]=await u.select({n:(0,c.count)()}).from(i).where((0,c.and)((0,c.eq)(i.tenantId,o),(0,c.isNull)(i.finishedAt))),v=y.filter(R=>!!R.isSyncEnabled),D=v.map(R=>R.syncedAt?K(R.syncedAt).getTime():null),x=D.length>0&&D.every(R=>R!==null)?Math.min(...D):null,V=y.length>0&&v.length===0||v.length>0&&(x===null||Date.now()-x>d.stalenessThresholdSec*1e3);return{isEnabled:d.isEnabled,provider:d.provider,linkedGroupCount:y.length,...x!==null?{oldestSyncedAt:new Date(x).toISOString()}:{},isStale:V,pausedGroupCount:y.length-v.length,stalenessThresholdSec:d.stalenessThresholdSec,erroredGroupIds:y.filter(R=>!!R.syncError).map(R=>Number(R.groupId)).sort((R,Ae)=>R-Ae),pendingRequestCount:Number(h?.n??0)}},async loadTenantMembershipPolicy(o){(0,G.assertTenantId)(o,"loadTenantMembershipPolicy(tenantId)");let y=b>0?f.get(o):void 0;if(y&&Date.now()-y.loadedAt<b)return y.policy;await s();let h=await u.select({groupId:r.groupId,isBreakGlass:r.isBreakGlass,externalLinkId:a.id}).from(r).innerJoin(l,(0,c.and)((0,c.eq)(l.id,r.groupId),(0,c.eq)(l.tenantId,o))).leftJoin(a,(0,c.and)((0,c.eq)(a.groupId,r.groupId),(0,c.eq)(a.tenantId,o))).where((0,c.eq)(r.tenantId,o));if(h.length===0){let C={kind:"no-proof-required"};return b>0&&f.set(o,{policy:C,loadedAt:Date.now()}),C}let v=h.map(C=>Number(C.groupId)),D=h.filter(C=>!!C.isBreakGlass);for(let C of D)if(C.externalLinkId!==null)throw new Error(`Break-glass group ${Number(C.groupId)} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`);let x={kind:"require-proof",proofGroupIds:v,breakGlassGroupIds:D.map(C=>Number(C.groupId))};return(0,fe.assertTenantMembershipPolicy)(x,`tenant ${o}`),b>0&&f.set(o,{policy:x,loadedAt:Date.now()}),x},async setTenantMembershipGroup(o,y,h,v){(0,G.assertTenantId)(o,"setTenantMembershipGroup(tenantId)"),await s(),await u.transaction(async D=>{if(await E(D,o,y),h){let[C]=await D.select({id:a.id}).from(a).where((0,c.and)((0,c.eq)(a.tenantId,o),(0,c.eq)(a.groupId,y)));if(C)throw new Error(`Group ${y} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`)}let x=await D.select({groupId:r.groupId}).from(r).where((0,c.and)((0,c.eq)(r.tenantId,o),(0,c.eq)(r.groupId,y)));if(!h&&!(await D.select({groupId:r.groupId,isBreakGlass:r.isBreakGlass}).from(r).where((0,c.eq)(r.tenantId,o))).filter(R=>Number(R.groupId)!==y).some(R=>!!R.isBreakGlass))throw new Error(`Declaring group ${y} as ordinary proof would leave tenant ${o} with a membership proof but no break-glass path; declare a locally-managed break-glass group first.`);if(x.length>0){await D.update(r).set({isBreakGlass:h,updatedAt:new Date,updatedBy:v}).output().where((0,c.and)((0,c.eq)(r.tenantId,o),(0,c.eq)(r.groupId,y)));return}await D.insert(r).output().values({tenantId:o,groupId:y,isBreakGlass:h,createdAt:new Date,createdBy:v})}),S(o)},async removeTenantMembershipGroup(o,y){(0,G.assertTenantId)(o,"removeTenantMembershipGroup(tenantId)"),await s(),await u.transaction(async h=>{let D=(await h.select({groupId:r.groupId,isBreakGlass:r.isBreakGlass}).from(r).where((0,c.eq)(r.tenantId,o))).filter(x=>Number(x.groupId)!==y);if(D.length>0&&!D.some(x=>!!x.isBreakGlass))throw new Error(`Removing group ${y} would leave tenant ${o} with a membership proof but no break-glass path.`);await h.delete(r).where((0,c.and)((0,c.eq)(r.tenantId,o),(0,c.eq)(r.groupId,y)))}),S(o)},async setGroupActive(o,y,h,v){(0,G.assertTenantId)(o,"setGroupActive(tenantId)"),await s(),await u.update(l).set({isActive:h,updatedAt:new Date,updatedBy:v}).output().where((0,c.and)((0,c.eq)(l.id,y),(0,c.eq)(l.tenantId,o)))},async listLedgerGroupIds(o,y){if((0,G.assertTenantId)(o,"listLedgerGroupIds(tenantId)"),!d.isEnabled)return[];await s();let h=await j(u,{ledger:g,group:l},{tenantId:o,externalUserId:y.externalUserId?.trim()||null,email:(0,ee.normalizeAuthEmail)(y.email)});return[...new Set(h.map(v=>v.groupId))].sort((v,D)=>v-D)},async isEmailAllowedByGroup(o){if(!d.isEnabled)return!1;let y=(0,ee.normalizeAuthEmail)(o);if(y==="")return!1;await s();let[h]=await u.select({id:g.id}).from(g).innerJoin(n,(0,c.eq)(n.groupId,g.groupId)).innerJoin(l,(0,c.and)((0,c.eq)(l.id,g.groupId),(0,c.eq)(l.isActive,!0))).where((0,c.eq)(g.email,y));return!!h},async listAllowlistGroups(o){return(0,G.assertTenantId)(o,"listAllowlistGroups(tenantId)"),await s(),(await u.select({id:n.id,groupId:n.groupId,groupKey:l.groupKey,groupName:l.name,description:n.description}).from(n).innerJoin(l,(0,c.and)((0,c.eq)(l.id,n.groupId),(0,c.eq)(l.tenantId,o))).where((0,c.eq)(n.tenantId,o)).orderBy((0,c.asc)(l.name))).map(h=>({id:Number(h.id),type:"group",groupId:Number(h.groupId),groupKey:String(h.groupKey),groupName:String(h.groupName),...h.description?{description:String(h.description)}:{},owner:{kind:"tenant",tenantId:o},readOnly:!1}))},async addAllowlistGroup(o,y,h,v){(0,G.assertTenantId)(o,"addAllowlistGroup(tenantId)"),await s(),await u.transaction(async D=>{await E(D,o,y);let[x]=await D.select({id:a.id}).from(a).where((0,c.and)((0,c.eq)(a.groupId,y),(0,c.eq)(a.tenantId,o)));if(!x)throw new Error(`Group ${y} is locally managed; only externally-sourced groups can gate sign-in, because the decision reads the upstream member ledger.`);await D.insert(n).output().values({tenantId:o,groupId:y,description:h??null,createdAt:new Date,createdBy:v})})},async removeAllowlistGroup(o,y){(0,G.assertTenantId)(o,"removeAllowlistGroup(tenantId)"),await s(),await u.delete(n).where((0,c.and)((0,c.eq)(n.id,y),(0,c.eq)(n.tenantId,o)))},async countProjectedMembers(o,y){(0,G.assertTenantId)(o,"countProjectedMembers(tenantId)"),await s();let[h]=await u.select({n:(0,c.count)()}).from(I).innerJoin(l,(0,c.and)((0,c.eq)(l.id,I.groupId),(0,c.eq)(l.tenantId,o))).where((0,c.eq)(I.groupId,y));return Number(h?.n??0)}}}var we=require("@aiquants/auth-core"),re=require("@aiquants/authz-core");async function qe(e,t){let m=(0,re.assertTenantId)(t.tenantId,"promoteLedgerForUser(tenantId)");if(!Number.isInteger(t.userId)||t.userId<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] userId must be a positive integer, received ${String(t.userId)}`);let d=(0,we.normalizeAuthEmail)(t.email),u=t.externalUserId?.trim()||null;if(u===null&&d==="")return{addedGroupIds:[],matchedLedgerIds:[]};let s=await e.findLedgerMatches({tenantId:m,externalUserId:u,email:d});if(s.length===0)return{addedGroupIds:[],matchedLedgerIds:[]};for(let a of s)(0,re.assertTenantMatch)(m,a.tenantId,"promoteLedgerForUser(findLedgerMatches row)");let b=[...new Set(s.map(a=>a.ledgerId))].sort((a,g)=>a-g),f=[...new Set(s.map(a=>a.groupId))].sort((a,g)=>a-g);return{addedGroupIds:[...await e.attachUserToGroups({tenantId:m,userId:t.userId,ledgerIds:b,groupIds:f})].sort((a,g)=>a-g),matchedLedgerIds:b}}var ue=require("@aiquants/authz-core"),P=require("drizzle-orm");var Oe=4,Ue=100;function ze(e,t,m,d){let u=e,s=d.ensureConnection??(async()=>{}),b=d.now??(()=>new Date),f=t.TDGroupMemberEmail,{TMGroup:S,TDGroupMember:a}=m;return{async findLedgerMatches(g){return(0,ue.assertTenantId)(g.tenantId,"findLedgerMatches(tenantId)"),await s(),j(u,{ledger:f,group:S},g)},async attachUserToGroups({tenantId:g,userId:r,ledgerIds:n,groupIds:i}){return(0,ue.assertTenantId)(g,"attachUserToGroups(tenantId)"),await s(),n.length===0?[]:u.transaction(async l=>{let I=new Set;for(let o of L(i)){let y=await l.select({id:S.id}).from(S).where((0,P.and)((0,P.inArray)(S.id,o),(0,P.eq)(S.tenantId,g),(0,P.eq)(S.isActive,!0)));for(let h of y)I.add(Number(h.id))}let w=i.filter(o=>I.has(o));if(w.length===0)return[];let E=new Set;for(let o of L(w)){let y=await l.select({groupId:a.groupId}).from(a).where((0,P.and)((0,P.eq)(a.userId,r),(0,P.inArray)(a.groupId,o)));for(let h of y)E.add(Number(h.groupId))}let T=w.filter(o=>!E.has(o)),k=Math.max(1,2100-Ue-w.length);for(let o of L(n,k))await l.update(f).set({resolvedUserId:r}).output().where((0,P.and)((0,P.inArray)(f.id,o),(0,P.inArray)(f.groupId,w)));if(T.length>0){let o=b();for(let y of N(T,Oe))await l.insert(a).output().values(y.map(h=>({groupId:h,userId:r,createdAt:o,createdBy:d.actor})))}return T})}}}var O=require("@aiquants/authz-drizzle"),p=require("drizzle-orm/mssql-core"),te="provider",Be=["TDGroupExternalLink","TDTenantMembershipGroup","TDAllowlistGroup","TDDirectorySyncRequest","TDDirectoryCatalog","TMDirectoryCatalogObservation","TMAllowlist"];function Fe(e,t){let m=(0,p.mssqlSchema)(e),d=()=>({createdAt:(0,p.datetime2)("created_at"),createdBy:(0,p.nvarchar)("created_by",{length:50}),updatedAt:(0,p.datetime2)("updated_at"),updatedBy:(0,p.nvarchar)("updated_by",{length:50})}),u=()=>({createdAt:(0,p.datetime2)("created_at"),createdBy:(0,p.nvarchar)("created_by",{length:50})}),s=m.table("TDGroupExternalLink",{id:(0,p.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,p.bigint)("group_id",{mode:"number"}).notNull(),tenantId:(0,p.nvarchar)(O.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),provider:(0,p.nvarchar)(te,{length:32}).notNull(),externalId:(0,p.nvarchar)("external_id",{length:256}).notNull(),externalKey:(0,p.nvarchar)("external_key",{length:320}).notNull(),membershipMode:(0,p.nvarchar)("membership_mode",{length:16}).notNull(),isSyncEnabled:(0,p.bit)("is_sync_enabled").notNull(),syncedAt:(0,p.datetime2)("synced_at"),syncError:(0,p.nvarchar)("sync_error",{length:1e3}),vanishedObservations:(0,p.int)("vanished_observations").notNull(),...d()},i=>[(0,p.primaryKey)({name:`${e}_TDGroupExternalLink_pk`,columns:[i.id]}),(0,p.uniqueIndex)(`${e}_TDGroupExternalLink_group_uq`).on(i.groupId),(0,p.uniqueIndex)(`${e}_TDGroupExternalLink_external_uq`).on(i.tenantId,i.provider,i.externalId),(0,p.foreignKey)({name:`${e}_TDGroupExternalLink_group_id_fk`,columns:[i.groupId],foreignColumns:[t.groupTable.id]})]),b=m.table("TDGroupMemberEmail",{id:(0,p.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,p.bigint)("group_id",{mode:"number"}).notNull(),email:(0,p.nvarchar)("email",{length:320}).notNull(),externalUserId:(0,p.nvarchar)("external_user_id",{length:128}),resolvedUserId:(0,p.bigint)("resolved_user_id",{mode:"number"}),observedAt:(0,p.datetime2)("observed_at").notNull(),...d()},i=>[(0,p.primaryKey)({name:`${e}_TDGroupMemberEmail_pk`,columns:[i.id]}),(0,p.uniqueIndex)(`${e}_TDGroupMemberEmail_group_email_uq`).on(i.groupId,i.email),(0,p.foreignKey)({name:`${e}_TDGroupMemberEmail_group_id_fk`,columns:[i.groupId],foreignColumns:[t.groupTable.id]})]),f=m.table("TDTenantMembershipGroup",{tenantId:(0,p.nvarchar)(O.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,p.bigint)("group_id",{mode:"number"}).notNull(),isBreakGlass:(0,p.bit)("is_break_glass").notNull(),...u()},i=>[(0,p.primaryKey)({name:`${e}_TDTenantMembershipGroup_pk`,columns:[i.tenantId,i.groupId]}),(0,p.foreignKey)({name:`${e}_TDTenantMembershipGroup_group_id_fk`,columns:[i.groupId],foreignColumns:[t.groupTable.id]})]),S=m.table("TDAllowlistGroup",{id:(0,p.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,p.nvarchar)(O.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,p.bigint)("group_id",{mode:"number"}).notNull(),description:(0,p.nvarchar)("description",{length:512}),...u()},i=>[(0,p.primaryKey)({name:`${e}_TDAllowlistGroup_pk`,columns:[i.id]}),(0,p.uniqueIndex)(`${e}_TDAllowlistGroup_tenant_group_uq`).on(i.tenantId,i.groupId),(0,p.foreignKey)({name:`${e}_TDAllowlistGroup_group_id_fk`,columns:[i.groupId],foreignColumns:[t.groupTable.id]})]),a=m.table("TDDirectorySyncRequest",{id:(0,p.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,p.nvarchar)(O.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,p.bigint)("group_id",{mode:"number"}),requestedBy:(0,p.nvarchar)("requested_by",{length:320}).notNull(),requestedAt:(0,p.datetime2)("requested_at").notNull(),pickedAt:(0,p.datetime2)("picked_at"),finishedAt:(0,p.datetime2)("finished_at"),result:(0,p.nvarchar)("result",{length:32}),error:(0,p.nvarchar)("error",{length:2e3}),...u()},i=>[(0,p.primaryKey)({name:`${e}_TDDirectorySyncRequest_pk`,columns:[i.id]})]),g=m.table("TMAllowlist",{id:(0,p.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,p.nvarchar)(O.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),pattern:(0,p.nvarchar)("pattern",{length:256}).notNull(),type:(0,p.nvarchar)("type",{length:32}).notNull(),description:(0,p.nvarchar)("description",{length:512}),...u()},i=>[(0,p.primaryKey)({name:`${e}_TMAllowlist_pk`,columns:[i.id]}),(0,p.uniqueIndex)(`${e}_TMAllowlist_pattern_uq`).on(i.tenantId,i.pattern)]),r=m.table("TDDirectoryCatalog",{id:(0,p.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,p.nvarchar)(O.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),provider:(0,p.nvarchar)(te,{length:32}).notNull(),externalId:(0,p.nvarchar)("external_id",{length:256}).notNull(),externalKey:(0,p.nvarchar)("external_key",{length:320}).notNull(),name:(0,p.nvarchar)("name",{length:256}).notNull(),description:(0,p.nvarchar)("description",{length:1e3}),memberCount:(0,p.int)("member_count"),observedAt:(0,p.datetime2)("observed_at").notNull(),...u()},i=>[(0,p.primaryKey)({name:`${e}_TDDirectoryCatalog_pk`,columns:[i.id]}),(0,p.uniqueIndex)(`${e}_TDDirectoryCatalog_external_uq`).on(i.tenantId,i.provider,i.externalId)]),n=m.table("TMDirectoryCatalogObservation",{id:(0,p.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,p.nvarchar)(O.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),provider:(0,p.nvarchar)(te,{length:32}).notNull(),observedAt:(0,p.datetime2)("observed_at").notNull(),entryCount:(0,p.int)("entry_count").notNull(),...d()},i=>[(0,p.primaryKey)({name:`${e}_TMDirectoryCatalogObservation_pk`,columns:[i.id]}),(0,p.uniqueIndex)(`${e}_TMDirectoryCatalogObservation_target_uq`).on(i.tenantId,i.provider)]);return{TDGroupExternalLink:s,TDGroupMemberEmail:b,TDTenantMembershipGroup:f,TDAllowlistGroup:S,TDDirectorySyncRequest:a,TDDirectoryCatalog:r,TMDirectoryCatalogObservation:n,TMAllowlist:g}}var oe=require("@aiquants/auth-directory-core");function W(e){if(e instanceof Error&&(e.name==="AbortError"||e.name==="TimeoutError"))return"timeout";let t=typeof e=="object"&&e!==null&&"status"in e?e.status:void 0;return typeof t!="number"?"unknown":t===401||t===403?"denied":t===429||t===408?"rateLimited":t>=500?"upstreamError":"unknown"}var Ie=e=>`${e.length} \u4EF6`,de={denied:"\u8CC7\u683C\u60C5\u5831\u304C\u62D2\u5426\u3055\u308C\u307E\u3057\u305F",rateLimited:"\u547C\u3073\u51FA\u3057\u304C\u5236\u9650\u3055\u308C\u3066\u3044\u307E\u3059",upstreamError:"\u76F8\u624B\u5074\u304C\u5185\u90E8\u30A8\u30E9\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F",timeout:"\u5FDC\u7B54\u304C\u3042\u308A\u307E\u305B\u3093\u3067\u3057\u305F",localWriteError:"\u66F8\u304D\u8FBC\u307F\u304C\u62D2\u5426\u3055\u308C\u307E\u3057\u305F",unknown:"\u8A73\u7D30\u306F\u30B5\u30FC\u30D0\u30FC\u306E\u30ED\u30B0\u306B\u51FA\u3066\u3044\u307E\u3059"},le={upstreamUnreadable:e=>`\u4E0A\u6D41\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8AAD\u307F\u53D6\u308A\u306B\u5931\u6557\u3057\u307E\u3057\u305F (${de[e]})\u3002`,localWriteFailed:e=>`\u30ED\u30FC\u30AB\u30EB\u3078\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F (${de[e]})\u3002`,resolverIncomplete:(e,t)=>`\u4E0A\u6D41\u304C ${e} \u4EF6\u306E\u30E1\u30F3\u30D0\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F\u304C\u3001\u7A81\u5408\u7D50\u679C\u306F ${t} \u4EF6\u3067\u3057\u305F\u3002\u4EF6\u6570\u304C\u6E1B\u308B\u7A81\u5408\u306F\u3001\u89E3\u6C7A\u3067\u304D\u306A\u304B\u3063\u305F\u4EBA\u7269\u3092\u300C\u4E0A\u6D41\u304B\u3089\u6D88\u3048\u305F\u300D\u3068\u3057\u3066\u524A\u9664\u3057\u3066\u3057\u307E\u3046\u305F\u3081\u4E2D\u65AD\u3057\u307E\u3057\u305F\u3002\u89E3\u6C7A\u3067\u304D\u306A\u3044\u30E1\u30F3\u30D0\u30FC\u306F\u7701\u7565\u305B\u305A resolvedUserId: null \u3067\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002`,groupMissing:(e,t,m)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${e})\u3002\u9023\u7D9A ${t} \u56DE\u76EE\u3067\u3059\u3002${m} \u56DE\u306B\u9054\u3057\u305F\u6642\u70B9\u3067\u30B0\u30EB\u30FC\u30D7\u3092\u7121\u52B9\u5316\u3057\u307E\u3059\u3002`,groupVanished:(e,t)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C ${t} \u56DE\u9023\u7D9A\u3067\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F (${e})\u3002\u30B0\u30EB\u30FC\u30D7\u3092\u7121\u52B9\u5316\u3057\u307E\u3057\u305F\u3002\u4E0A\u6D41\u304C\u5FA9\u65E7\u3059\u308C\u3070\u6B21\u56DE\u306E\u540C\u671F\u3067\u81EA\u52D5\u7684\u306B\u518D\u6709\u52B9\u5316\u3055\u308C\u307E\u3059\u3002`,planRefused:e=>{if(e.reason==="invalid-upstream-data")return`\u540C\u671F\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F: \u4E0A\u6D41\u306E\u30E1\u30F3\u30D0\u30FC\u4E00\u89A7\u306B\u6271\u3048\u306A\u3044\u30A2\u30C9\u30EC\u30B9\u304C ${Ie(e.offendingEmails)} \u542B\u307E\u308C\u3066\u3044\u307E\u3059\u3002\u5BFE\u8C61\u306F\u30B5\u30FC\u30D0\u30FC\u306E\u30ED\u30B0\u306B\u51FA\u3066\u3044\u307E\u3059\u3002`;let t=e.axis==="membership"?"\u6A29\u9650\u3092\u5931\u3046\u4EBA\u6570":"\u30B5\u30A4\u30F3\u30A4\u30F3\u3067\u304D\u306A\u304F\u306A\u308B\u4EBA\u6570",m=e.axis==="membership"?e.withheldProjectionRemoves.map(String):e.withheldLedgerDeletes;return[`\u540C\u671F\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F: ${t}\u304C ${e.population} \u4EBA\u4E2D ${e.removalCount} \u4EBA\u306B\u306A\u308A\u307E\u3059`,`(\u4E0A\u9650: ${e.limits.maxRemovalCount} \u4EF6 / \u6BD4\u7387 ${e.limits.maxRemovalRatio})\u3002`,`\u5DEE\u3057\u6B62\u3081\u305F\u5BFE\u8C61: ${Ie(m)} (\u4E00\u89A7\u306F\u30B5\u30FC\u30D0\u30FC\u306E\u30ED\u30B0\u306B\u51FA\u3066\u3044\u307E\u3059)\u3002`,"\u4E0A\u6D41\u5074\u306E\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u610F\u56F3\u3057\u305F\u5909\u66F4\u3067\u3042\u308C\u3070\u3001\u3053\u306E\u8EF8\u306E\u4E0A\u9650\u3060\u3051\u3092\u4E00\u6642\u7684\u306B\u5F15\u304D\u4E0A\u3052\u3066\u518D\u5B9F\u884C\u3057\u307E\u3059\u3002"].join(" ")},removalWritesFailed:e=>`${e.length} \u4EF6\u306E\u6240\u5C5E\u89E3\u9664\u304C\u66F8\u304D\u8FBC\u3081\u307E\u305B\u3093\u3067\u3057\u305F (${[...new Set(e.map(t=>de[t.cause]))].join(" / ")})\u3002\u6B21\u56DE\u306E\u5B9F\u884C\u3067\u518D\u8A66\u884C\u3057\u307E\u3059\u3002`,removalsRefused:e=>`${e.length} \u4EF6\u306E\u6240\u5C5E\u89E3\u9664\u304C\u6700\u5F8C\u306E\u7BA1\u7406\u8005\u30AC\u30FC\u30C9\u306B\u3088\u308A\u62D2\u5426\u3055\u308C\u307E\u3057\u305F (\u30E6\u30FC\u30B6\u30FC ${e.map(t=>t.userId).join(", ")})\u3002\u6B8B\u308A\u306E\u5909\u66F4\u306F\u9069\u7528\u6E08\u307F\u3067\u3059\u3002`,foreignProvider:(e,t)=>`\u3053\u306E\u30EA\u30F3\u30AF\u306E\u4F9B\u7D66\u5143\u306F ${e} \u3067\u3059\u304C\u3001\u5B9F\u884C\u4E2D\u306E\u540C\u671F\u306F ${t} \u7528\u3067\u3059\u3002\u5BFE\u5FDC\u3059\u308B\u540C\u671F\u30B8\u30E7\u30D6\u304B\u3089\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002`};var ne=["aborted","missing","vanished","upstream-failed","local-failed","foreign-provider","not-converged"],ce=[...ne,"already-vanished"];function je(e){let{directory:t,repository:m,policy:d,now:u,logger:s}=e,b=e.messages??le;if((0,oe.assertBlastRadiusPolicy)(d),!Number.isInteger(e.vanishedThreshold)||e.vanishedThreshold<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] vanishedThreshold must be a positive integer, received ${String(e.vanishedThreshold)}`);if(typeof e.provider!="string"||e.provider.trim()==="")throw new TypeError("[@aiquants/auth-directory-drizzle] provider must be a non-empty string so links of other providers can be told apart");async function f(r,n){try{await m.recordFailure(r,n)}catch(i){s.error(`[auth-directory] could not record the failure for ${r.externalKey}:`,i)}}async function S(r){try{let n=await t.getGroup(r.externalId);return n===null?{kind:"missing"}:{kind:"ok",group:n,members:await t.listGroupMembers(n,r.membershipMode)}}catch(n){return{kind:"failed",error:n instanceof Error?n:new Error(String(n))}}}async function a(r){if(r.vanishedObservations>=e.vanishedThreshold&&!r.isGroupActive)return s.warn(`[auth-directory] ${r.externalKey} still missing upstream (already deactivated after ${r.vanishedObservations} absences)`),{kind:"already-vanished",link:r};let n=await m.recordVanishedObservation(r,b.groupMissing(r.externalKey,r.vanishedObservations+1,e.vanishedThreshold));return n<e.vanishedThreshold?(s.warn(`[auth-directory] ${r.externalKey} missing upstream (${n}/${e.vanishedThreshold})`),{kind:"missing",link:r,observations:n}):(await m.markGroupInactive(r),await f(r,b.groupVanished(r.externalKey,n)),s.warn(`[auth-directory] ${r.externalKey} deactivated after ${n} consecutive absences`),{kind:"vanished",link:r})}async function g(r){if(r.provider!==e.provider)return await f(r,b.foreignProvider(r.provider,e.provider)),s.warn(`[auth-directory] skipping ${r.externalKey}: belongs to provider ${r.provider}`),{kind:"foreign-provider",link:r};let n=await S(r);if(n.kind==="missing")return a(r);if(n.kind==="failed")return await f(r,b.upstreamUnreadable(W(n.error))),s.error(`[auth-directory] upstream read failed for ${r.externalKey}:`,n.error),{kind:"upstream-failed",link:r,error:n.error};try{await m.resolveExternalIdentity(r,n.group);let[i,l]=await Promise.all([m.loadGroupSnapshot(r),m.resolveMembers(n.members)]);if(l.length!==n.members.length){let k=b.resolverIncomplete(n.members.length,l.length);return await f(r,k),s.error(`[auth-directory] ${k}`),{kind:"local-failed",link:r,error:new Error(k)}}let I=(0,oe.reconcile)(i,l,d);if(I.aborted){await f(r,b.planRefused(I.aborted));let k=I.aborted.reason==="invalid-upstream-data"?I.aborted.offendingEmails:I.aborted.axis==="membership"?I.aborted.withheldProjectionRemoves.map(String):I.aborted.withheldLedgerDeletes;return s.warn(`[auth-directory] plan refused for ${r.externalKey}: ${I.aborted.reason}; withheld: ${k.join(", ")}`),{kind:"aborted",link:r,plan:I}}let w=I.ledgerUpserts.length>0||I.ledgerDeletes.length>0||I.projectionAdds.length>0||I.projectionRemoves.length>0,E=u(),T={refusals:[],failures:[]};return w&&(T=await m.applyPlan(r,I,E)),await m.recordSuccess(r,n.group,E),T.refusals.length>0&&(await f(r,b.removalsRefused(T.refusals)),s.warn(`[auth-directory] ${T.refusals.length} removal(s) refused for ${r.externalKey}: users ${T.refusals.map(k=>k.userId).join(", ")}`)),T.failures.length>0&&(await f(r,b.removalWritesFailed(T.failures)),s.warn(`[auth-directory] ${T.failures.length} removal(s) could not be written for ${r.externalKey}: users ${T.failures.map(k=>k.userId).join(", ")}`)),I.unresolvedEmails.length>0&&s.info(`[auth-directory] ${r.externalKey}: ${I.unresolvedEmails.length} upstream member(s) have no local user yet`),T.refusals.length>0||T.failures.length>0?{kind:"not-converged",link:r,plan:I,refusals:T.refusals,failures:T.failures}:w?{kind:"applied",link:r,plan:I}:{kind:"unchanged",link:r}}catch(i){let l=i instanceof Error?i:new Error(String(i));return await f(r,b.localWriteFailed("localWriteError")),s.error(`[auth-directory] local write failed for ${r.externalKey}:`,l),{kind:"local-failed",link:r,error:l}}}return{syncOne:g,async run(r){let n=await m.listSyncableLinks(r),i=[];for(let w of n)try{i.push(await g(w))}catch(E){let T=E instanceof Error?E:new Error(String(E));s.error(`[auth-directory] ${w.externalKey} ended abnormally:`,T),i.push({kind:"local-failed",link:w,error:T})}let l=i.filter(w=>ce.includes(w.kind)).length,I=i.filter(w=>ne.includes(w.kind)).length;return s.info(`[auth-directory] run finished: ${i.length} link(s), ${l} unhealthy (${I} new)`),{outcomes:i,unhealthyCount:l,newlyUnhealthyCount:I}}}}var Se=require("@aiquants/authz-core"),M=require("drizzle-orm");var ve="The job that claimed this request ended without recording an outcome; whether the synchronization ran is unknown.",pe=2e3;function We(e,t,m){let d=e,u=m.ensureConnection??(async()=>{}),s=t.TDDirectorySyncRequest,b=(0,Se.assertTenantId)(m.tenantId,"createSyncRequestQueue(tenantId)"),f=m.maxErrorLength??pe;if(!Number.isInteger(f)||f<1||f>pe)throw new TypeError(`[@aiquants/auth-directory-drizzle] maxErrorLength must be an integer within 1..${pe}, received ${String(m.maxErrorLength)}`);let S={async claim(){await u();let a=await d.select({id:s.id}).from(s).where((0,M.and)((0,M.eq)(s.tenantId,b),(0,M.isNull)(s.pickedAt))).orderBy((0,M.asc)(s.id));for(let g of a){let n=(await d.update(s).set({pickedAt:m.now()}).output().where((0,M.and)((0,M.eq)(s.tenantId,b),(0,M.eq)(s.id,Number(g.id)),(0,M.isNull)(s.pickedAt))))?.[0];if(!n)continue;if(n.requestedBy===void 0||n.requestedBy===null)throw new TypeError(`[@aiquants/auth-directory-drizzle] the driver returned a row without requestedBy for request ${String(n.id)}`);let i=n.groupId??null;return{id:Number(n.id),tenantId:b,groupId:i===null?null:Number(i),requestedBy:String(n.requestedBy)}}return null},async finish(a,g){await u();let r=g.error?g.error.slice(0,f):null;await d.update(s).set({finishedAt:m.now(),result:g.result,error:r}).output().where((0,M.and)((0,M.eq)(s.tenantId,b),(0,M.eq)(s.id,a),(0,M.isNull)(s.finishedAt)))},async listStranded(a){await u();let g=await d.select({id:s.id,pickedAt:s.pickedAt,requestedAt:s.requestedAt}).from(s).where((0,M.and)((0,M.eq)(s.tenantId,b),(0,M.isNull)(s.finishedAt))).orderBy((0,M.asc)(s.id)),r=n=>{let i=K(n);return Number.isNaN(i.getTime())||i<a};return{stranded:g.filter(n=>n.pickedAt!==null&&r(n.pickedAt)).map(n=>Number(n.id)),unclaimed:g.filter(n=>n.pickedAt===null&&r(n.requestedAt)).map(n=>Number(n.id))}},async abandonStranded(a){let{stranded:g}=await S.listStranded(a),r=[];for(let n of g)try{await S.finish(n,{result:"failed",error:ve}),r.push(n)}catch(i){m.onCloseFailed?.(n,i)}return r}};return S}var H=require("@aiquants/auth-core"),J=require("@aiquants/authz-core"),A=require("drizzle-orm");var He=7,Je=4;function Ve(e){if(!(e instanceof Error))return!1;let t=e;return t.number===void 0&&t.code===void 0&&e.name==="Error"}function Ye(e,t,m,d){let u=e,s=d.ensureConnection??(async()=>{}),b=d.now??(()=>new Date),{TDGroupExternalLink:f,TDGroupMemberEmail:S}=t,{TMGroup:a,TDGroupMember:g}=m,r=d.actor;return{async listSyncableLinks(n){await s();let i=(0,J.assertTenantId)(n.tenantId,"listSyncableLinks(tenantId)"),l=[(0,A.eq)(f.isSyncEnabled,!0),(0,A.eq)(f.tenantId,i)];return n.groupId!==void 0&&l.push((0,A.eq)(f.groupId,n.groupId)),(await u.select({linkId:f.id,groupId:f.groupId,linkTenantId:f.tenantId,groupTenantId:a.tenantId,groupKey:a.groupKey,isGroupActive:a.isActive,provider:f.provider,externalId:f.externalId,externalKey:f.externalKey,membershipMode:f.membershipMode,vanishedObservations:f.vanishedObservations}).from(f).innerJoin(a,(0,A.and)((0,A.eq)(a.id,f.groupId),(0,A.eq)(a.tenantId,i))).where((0,A.and)(...l))).map(w=>((0,J.assertTenantMatch)(String(w.groupTenantId),String(w.linkTenantId),"listSyncableLinks(link.tenantId vs TMGroup.tenant_id)"),{linkId:Number(w.linkId),groupId:Number(w.groupId),groupKey:String(w.groupKey),tenantId:String(w.groupTenantId),provider:String(w.provider),externalId:String(w.externalId),externalKey:String(w.externalKey),membershipMode:z(String(w.membershipMode)),isGroupActive:!!w.isGroupActive,vanishedObservations:Number(w.vanishedObservations??0)}))},async loadGroupSnapshot(n){await s();let[i,l]=await Promise.all([u.select({email:S.email,externalUserId:S.externalUserId,resolvedUserId:S.resolvedUserId}).from(S).where((0,A.eq)(S.groupId,n.groupId)),u.select({userId:g.userId}).from(g).where((0,A.eq)(g.groupId,n.groupId))]);return{ledger:i.map(I=>({email:String(I.email),...I.externalUserId?{externalUserId:String(I.externalUserId)}:{},resolvedUserId:I.resolvedUserId===null?null:Number(I.resolvedUserId)})),projectedUserIds:l.map(I=>Number(I.userId))}},resolveMembers(n){return d.memberResolver.resolve(n)},async applyPlan(n,i,l){(0,J.assertTenantId)(n.tenantId,"applyPlan(link.tenantId)"),await s(),(i.ledgerUpserts.length>0||i.projectionAdds.length>0)&&await u.transaction(async T=>{let k=i.ledgerUpserts.map(h=>({...h,email:(0,H.normalizeAuthEmail)(h.email)})),o=new Map;for(let h of L(k.map(v=>v.email))){let v=await T.select({id:S.id,email:S.email}).from(S).where((0,A.and)((0,A.eq)(S.groupId,n.groupId),(0,A.inArray)(S.email,h)));for(let D of v)o.set(String(D.email),Number(D.id))}let y=k.filter(h=>!o.has(h.email));for(let h of N(y,He))await T.insert(S).output().values(h.map(v=>({groupId:n.groupId,email:v.email,externalUserId:v.externalUserId??null,resolvedUserId:v.resolvedUserId,observedAt:l,createdAt:l,createdBy:r})));for(let h of k){let v=o.get(h.email);v!==void 0&&await T.update(S).set({externalUserId:h.externalUserId??null,resolvedUserId:h.resolvedUserId,observedAt:l,updatedAt:l,updatedBy:r}).output().where((0,A.eq)(S.id,v))}for(let h of N(i.projectionAdds,Je)){let v=new Set((await T.select({userId:g.userId}).from(g).where((0,A.and)((0,A.eq)(g.groupId,n.groupId),(0,A.inArray)(g.userId,h)))).map(x=>Number(x.userId))),D=h.filter(x=>!v.has(x));D.length>0&&await T.insert(g).output().values(D.map(x=>({groupId:n.groupId,userId:x,createdAt:l,createdBy:r})))}});let I=[],w=[];for(let T of i.projectionRemoves)try{await d.lockoutGuard.guardedWrite(n.tenantId,{removeGroupMembership:{groupId:n.groupId,userId:T}},"remove-group-member",k=>k.delete(g).where((0,A.and)((0,A.eq)(g.groupId,n.groupId),(0,A.eq)(g.userId,T))))}catch(k){Ve(k)?I.push({userId:T,applied:!1,refusal:k.message}):w.push({userId:T,cause:W(k)})}let E=I.map(T=>T.userId);if(i.ledgerDeletes.length>0){let T=Math.max(1,1999-E.length);await u.transaction(async k=>{for(let o of L(i.ledgerDeletes,Math.min(500,T))){let y=E.length>0?(0,A.or)((0,A.isNull)(S.resolvedUserId),(0,A.notInArray)(S.resolvedUserId,E)):void 0;await k.delete(S).where((0,A.and)((0,A.eq)(S.groupId,n.groupId),(0,A.inArray)(S.email,o),...y?[y]:[]))}})}return{refusals:I,failures:w}},async resolveExternalIdentity(n,i){await s(),!(n.externalId===i.externalId&&n.externalKey===(0,H.normalizeAuthEmail)(i.externalKey))&&await u.update(f).set({externalId:i.externalId,externalKey:(0,H.normalizeAuthEmail)(i.externalKey)}).output().where((0,A.and)((0,A.eq)(f.id,n.linkId),(0,A.eq)(f.tenantId,n.tenantId)))},async recordSuccess(n,i,l){await s(),await u.transaction(async I=>{await I.update(f).set({syncedAt:l,syncError:null,vanishedObservations:0,externalId:i.externalId,externalKey:(0,H.normalizeAuthEmail)(i.externalKey),updatedAt:l,updatedBy:r}).output().where((0,A.and)((0,A.eq)(f.id,n.linkId),(0,A.eq)(f.tenantId,n.tenantId))),n.isGroupActive||await I.update(a).set({isActive:!0,updatedAt:l,updatedBy:r}).output().where((0,A.and)((0,A.eq)(a.id,n.groupId),(0,A.eq)(a.tenantId,n.tenantId)))})},async recordFailure(n,i){await s(),await u.update(f).set({syncError:i.slice(0,1e3),updatedAt:b(),updatedBy:r}).output().where((0,A.and)((0,A.eq)(f.id,n.linkId),(0,A.eq)(f.tenantId,n.tenantId)))},async recordVanishedObservation(n,i){await s();let l=n.vanishedObservations+1;return await u.update(f).set({vanishedObservations:l,syncError:i.slice(0,1e3),updatedAt:b(),updatedBy:r}).output().where((0,A.and)((0,A.eq)(f.id,n.linkId),(0,A.eq)(f.tenantId,n.tenantId))),l},async markGroupInactive(n){await s(),await u.update(a).set({isActive:!1,updatedAt:b(),updatedBy:r}).output().where((0,A.and)((0,A.eq)(a.id,n.groupId),(0,A.eq)(a.tenantId,n.tenantId),(0,A.eq)(a.isActive,!0)))}}}0&&(module.exports={AUTH_DIRECTORY_PROVIDER_COLUMN,AUTH_DIRECTORY_TENANT_SCOPED_TABLES,MAX_IN_LIST,MAX_PARAMETERS,MEMBERSHIP_MODES,NEWLY_UNHEALTHY_SYNC_OUTCOMES,RESERVED_PARAMETERS,STRANDED_REASON,UNHEALTHY_SYNC_OUTCOMES,assertGroupMayBeLinked,assertMembershipMode,chunk,chunkByParameters,classifySyncFailure,createDirectoryCatalogReader,createDirectoryCatalogWriter,createDirectoryLinkStore,createDirectorySync,createDirectorySyncRepository,createPromotionRepository,createSyncRequestQueue,defaultExternalGroupGuardMessage,defaultSyncMessages,defineAuthDirectorySchema,findLedgerRowsForIdentity,promoteLedgerForUser,toInstant,withExternalGroupGuards});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|