@aiquants/auth-directory-drizzle 0.6.0 → 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 +7 -7
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var F=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var ce=Object.prototype.hasOwnProperty;var me=(t,o)=>{for(var g in o)F(t,g,{get:o[g],enumerable:!0})},ye=(t,o,g,h)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of pe(o))!ce.call(t,s)&&s!==g&&F(t,s,{get:()=>o[s],enumerable:!(h=le(o,s))||h.enumerable});return t};var ge=t=>ye(F({},"__esModule",{value:!0}),t);var Re={};me(Re,{AUTH_DIRECTORY_PROVIDER_COLUMN:()=>ae,AUTH_DIRECTORY_TENANT_SCOPED_TABLES:()=>Te,MAX_IN_LIST:()=>qe,MAX_PARAMETERS:()=>se,MEMBERSHIP_MODES:()=>W,UNHEALTHY_SYNC_OUTCOMES:()=>Z,assertGroupMayBeLinked:()=>we,assertMembershipMode:()=>K,chunk:()=>L,chunkByParameters:()=>N,createDirectoryLinkStore:()=>fe,createDirectorySync:()=>xe,createDirectorySyncRepository:()=>Me,createPromotionRepository:()=>ve,createSyncRequestQueue:()=>ke,defaultExternalGroupGuardMessage:()=>he,defaultSyncMessages:()=>Q,defineAuthDirectorySchema:()=>De,findLedgerRowsForIdentity:()=>z,promoteLedgerForUser:()=>Ie,withExternalGroupGuards:()=>be});module.exports=ge(Re);var te=require("@aiquants/authz-core"),he=(t,o)=>`\u5916\u90E8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u9023\u643A\u30B0\u30EB\u30FC\u30D7 (${o}) \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 H(t,o,g,h){return new Set(t.filter(s=>s.roleId===o&&s.appKey===g&&s.resourceKey===h).map(s=>s.action))}var J=t=>te.AUTHZ_ACTIONS.every(o=>t.has(o)),V=(t,o)=>t.find(g=>g.roleId===o)?.roleKey??`#${o}`;function be(t,o){return ne(t,o)}function ne(t,o){let g=t;async function h(s,a,p,y,w){if(y.size===0)return;let n=await s.listGroupRoles(p),b=new Set;for(let e of n){if(!y.has(e.roleId)||b.has(e.groupId))continue;b.add(e.groupId);let l=await o.linkLookup.externalGroupKey(p,e.groupId,a);if(l!==null)throw new Error(o.message(e.roleKey||V(w,e.roleId),l))}}return{...t,withTransaction:(s,a)=>g.withTransaction((p,y)=>s(ne(p,o),y),a),async assignGroupRole(s,a,p,y){await g.withTransaction(async(w,n)=>{let b=await w.listGrants(s);if(J(H(b,p,o.adminAppKey,o.adminResourceKey))){let e=await o.linkLookup.externalGroupKey(s,a,n);if(e!==null)throw new Error(o.message(V(b,p),e))}await w.assignGroupRole(s,a,p,y)})},async createGrant(s,a,p){await g.withTransaction(async(y,w)=>{let b=(await y.listResources(s)).find(e=>e.id===a.resourceId);if(b?.appKey===o.adminAppKey&&b?.resourceKey===o.adminResourceKey){let e=await y.listGrants(s),l=H(e,a.roleId,o.adminAppKey,o.adminResourceKey);l.add(a.action),J(l)&&await h(y,w,s,new Set([a.roleId]),e)}await y.createGrant(s,a,p)})}}}async function we(t,o,g,h){let s=(await t.listGroupRoles(o)).filter(p=>p.groupId===g);if(s.length===0)return;let a=await t.listGrants(o);for(let p of s)if(J(H(a,p.roleId,h.adminAppKey,h.adminResourceKey)))throw new Error(h.message(p.roleKey||V(a,p.roleId),p.groupKey))}var $=require("drizzle-orm");async function z(t,o,g){let{ledger:h,group:s}=o,{tenantId:a,externalUserId:p,email:y}=g;if(p===null&&y==="")return[];let w={ledgerId:h.id,groupId:h.groupId,tenantId:s.tenantId,externalUserId:h.externalUserId},n=async d=>(await t.select(w).from(h).innerJoin(s,(0,$.and)((0,$.eq)(s.id,h.groupId),(0,$.eq)(s.tenantId,a),(0,$.eq)(s.isActive,!0))).where(d)).map(I=>({ledgerId:Number(I.ledgerId),groupId:Number(I.groupId),tenantId:String(I.tenantId),externalUserId:I.externalUserId===null?null:String(I.externalUserId)})),b=d=>{let v=new Map;for(let I of d)v.set(I.ledgerId,{ledgerId:I.ledgerId,groupId:I.groupId,tenantId:I.tenantId});return[...v.values()].sort((I,T)=>I.ledgerId-T.ledgerId)},e=p===null?[]:await n((0,$.eq)(h.externalUserId,p));if(y==="")return b(e);let l=await n((0,$.eq)(h.email,y)),A=d=>p!==null&&d.externalUserId!==null&&d.externalUserId!==p;return b([...e,...l.filter(d=>!A(d))])}var O=require("@aiquants/auth-core"),oe=require("@aiquants/auth-directory-core"),x=require("@aiquants/authz-core"),u=require("drizzle-orm");var W=["direct","transitive"];function K(t){if(!W.includes(t))throw new TypeError(`[@aiquants/auth-directory-drizzle] membershipMode must be one of ${W.join(" | ")}, received ${JSON.stringify(t)}`);return t}function fe(t,o,g,h){let s=t,a=h.ensureConnection??(async()=>{}),p=h.policyCacheTtlMs??0;if(!Number.isFinite(p)||p<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] policyCacheTtlMs must be a non-negative number, received ${String(h.policyCacheTtlMs)}`);let y=new Map,w=r=>y.delete(r),{TDGroupExternalLink:n,TDGroupMemberEmail:b,TDTenantMembershipGroup:e,TDAllowlistGroup:l,TDDirectorySyncRequest:A}=o,{TMGroup:d,TDGroupMember:v}=g;async function I(r,i,m){if((await r.select({groupId:e.groupId}).from(e).where((0,u.and)((0,u.eq)(e.tenantId,i),(0,u.eq)(e.groupId,m),(0,u.eq)(e.isBreakGlass,!0)))).length>0)throw new Error(`Group ${m} is a break-glass proof group; a break-glass proof path must be one the synchronization can never touch.`)}async function T(r,i,m){let[f]=await r.select({id:d.id}).from(d).where((0,u.and)((0,u.eq)(d.id,m),(0,u.eq)(d.tenantId,i)));if(!f)throw new Error(`Group not found in tenant: ${m}`)}function G(r,i){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:i}}async function _(r,i){let m=await r.select({groupId:b.groupId,n:(0,u.count)()}).from(b).innerJoin(d,(0,u.and)((0,u.eq)(d.id,b.groupId),(0,u.eq)(d.tenantId,i))).where((0,u.isNull)(b.resolvedUserId)).groupBy(b.groupId);return new Map(m.map(f=>[Number(f.groupId),Number(f.n)]))}return{async listLinks(r){(0,x.assertTenantId)(r,"listLinks(tenantId)"),await a();let i=await s.select({linkId:n.id,groupId:n.groupId,tenantId:n.tenantId,provider:n.provider,externalId:n.externalId,externalKey:n.externalKey,membershipMode:n.membershipMode,isSyncEnabled:n.isSyncEnabled,syncedAt:n.syncedAt,syncError:n.syncError}).from(n).where((0,u.eq)(n.tenantId,r)).orderBy((0,u.asc)(n.groupId)),m=await _(s,r);return i.map(f=>((0,x.assertTenantMatch)(r,String(f.tenantId),"listLinks(row.tenantId)"),G(f,m.get(Number(f.groupId))??0)))},async externalGroupKey(r,i,m){(0,x.assertTenantId)(r,"externalGroupKey(tenantId)"),await a();let[f]=await(m??s).select({externalKey:n.externalKey}).from(n).where((0,u.and)((0,u.eq)(n.groupId,i),(0,u.eq)(n.tenantId,r)));return f?String(f.externalKey):null},async linkGroup(r,i,m,f){(0,x.assertTenantId)(r,"linkGroup(tenantId)");let D=K(m.membershipMode),k=m.externalId.trim(),E=(0,O.normalizeAuthEmail)(m.externalKey);if(k===""||E==="")throw new TypeError("[@aiquants/auth-directory-drizzle] externalId and externalKey must be non-empty");await a(),await h.linkable.assertLinkableAndWrite(r,i,async j=>{let M=j;await T(M,r,i),await I(M,r,i),await M.insert(n).output().values({groupId:i,tenantId:r,provider:m.provider,externalId:k,externalKey:E,membershipMode:D,isSyncEnabled:!0,vanishedObservations:0,createdAt:new Date,createdBy:f})}),w(r)},async unlinkGroup(r,i){(0,x.assertTenantId)(r,"unlinkGroup(tenantId)"),await a(),await s.transaction(async m=>{await T(m,r,i),await m.delete(b).where((0,u.eq)(b.groupId,i)),await m.delete(l).where((0,u.and)((0,u.eq)(l.groupId,i),(0,u.eq)(l.tenantId,r))),await m.delete(n).where((0,u.and)((0,u.eq)(n.groupId,i),(0,u.eq)(n.tenantId,r)))}),w(r)},async setSyncEnabled(r,i,m,f){(0,x.assertTenantId)(r,"setSyncEnabled(tenantId)"),await a(),await s.update(n).set({isSyncEnabled:m,updatedAt:new Date,updatedBy:f}).output().where((0,u.and)((0,u.eq)(n.groupId,i),(0,u.eq)(n.tenantId,r)))},async requestSync(r,i,m){(0,x.assertTenantId)(r,"requestSync(tenantId)"),await a(),await s.transaction(async f=>{i!==null&&await T(f,r,i),await f.insert(A).output().values({tenantId:r,groupId:i,requestedBy:m,requestedAt:new Date,createdAt:new Date,createdBy:m})})},async getStatus(r){(0,x.assertTenantId)(r,"getStatus(tenantId)"),await a();let i=await s.select({groupId:n.groupId,isSyncEnabled:n.isSyncEnabled,syncedAt:n.syncedAt,syncError:n.syncError}).from(n).where((0,u.eq)(n.tenantId,r)),[m]=await s.select({n:(0,u.count)()}).from(A).where((0,u.and)((0,u.eq)(A.tenantId,r),(0,u.isNull)(A.finishedAt))),f=i.filter(M=>!!M.isSyncEnabled),D=f.map(M=>M.syncedAt?new Date(M.syncedAt).getTime():null),k=D.length>0&&D.every(M=>M!==null)?Math.min(...D):null,j=i.length>0&&f.length===0||f.length>0&&(k===null||Date.now()-k>h.stalenessThresholdSec*1e3);return{isEnabled:h.isEnabled,provider:h.provider,linkedGroupCount:i.length,...k!==null?{oldestSyncedAt:new Date(k).toISOString()}:{},isStale:j,pausedGroupCount:i.length-f.length,stalenessThresholdSec:h.stalenessThresholdSec,erroredGroupIds:i.filter(M=>!!M.syncError).map(M=>Number(M.groupId)).sort((M,ue)=>M-ue),pendingRequestCount:Number(m?.n??0)}},async loadTenantMembershipPolicy(r){(0,x.assertTenantId)(r,"loadTenantMembershipPolicy(tenantId)");let i=p>0?y.get(r):void 0;if(i&&Date.now()-i.loadedAt<p)return i.policy;await a();let m=await s.select({groupId:e.groupId,isBreakGlass:e.isBreakGlass,externalLinkId:n.id}).from(e).innerJoin(d,(0,u.and)((0,u.eq)(d.id,e.groupId),(0,u.eq)(d.tenantId,r))).leftJoin(n,(0,u.eq)(n.groupId,e.groupId)).where((0,u.eq)(e.tenantId,r));if(m.length===0){let E={kind:"no-proof-required"};return p>0&&y.set(r,{policy:E,loadedAt:Date.now()}),E}let f=m.map(E=>Number(E.groupId)),D=m.filter(E=>!!E.isBreakGlass);for(let E of D)if(E.externalLinkId!==null)throw new Error(`Break-glass group ${Number(E.groupId)} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`);let k={kind:"require-proof",proofGroupIds:f,breakGlassGroupIds:D.map(E=>Number(E.groupId))};return(0,oe.assertTenantMembershipPolicy)(k,`tenant ${r}`),p>0&&y.set(r,{policy:k,loadedAt:Date.now()}),k},async setTenantMembershipGroup(r,i,m,f){(0,x.assertTenantId)(r,"setTenantMembershipGroup(tenantId)"),await a(),await s.transaction(async D=>{if(await T(D,r,i),m){let[E]=await D.select({id:n.id}).from(n).where((0,u.and)((0,u.eq)(n.tenantId,r),(0,u.eq)(n.groupId,i)));if(E)throw new Error(`Group ${i} 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,u.and)((0,u.eq)(e.tenantId,r),(0,u.eq)(e.groupId,i)))).length>0){await D.update(e).set({isBreakGlass:m,updatedAt:new Date,updatedBy:f}).output().where((0,u.and)((0,u.eq)(e.tenantId,r),(0,u.eq)(e.groupId,i))),w(r);return}await D.insert(e).output().values({tenantId:r,groupId:i,isBreakGlass:m,createdAt:new Date,createdBy:f})}),w(r)},async removeTenantMembershipGroup(r,i){(0,x.assertTenantId)(r,"removeTenantMembershipGroup(tenantId)"),await a(),await s.transaction(async m=>{let D=(await m.select({groupId:e.groupId,isBreakGlass:e.isBreakGlass}).from(e).where((0,u.eq)(e.tenantId,r))).filter(k=>Number(k.groupId)!==i);if(D.length>0&&!D.some(k=>!!k.isBreakGlass))throw new Error(`Removing group ${i} would leave tenant ${r} with a membership proof but no break-glass path.`);await m.delete(e).where((0,u.and)((0,u.eq)(e.tenantId,r),(0,u.eq)(e.groupId,i)))}),w(r)},async setGroupActive(r,i,m,f){(0,x.assertTenantId)(r,"setGroupActive(tenantId)"),await a(),await s.update(d).set({isActive:m,updatedAt:new Date,updatedBy:f}).output().where((0,u.and)((0,u.eq)(d.id,i),(0,u.eq)(d.tenantId,r)))},async listLedgerGroupIds(r,i){if((0,x.assertTenantId)(r,"listLedgerGroupIds(tenantId)"),!h.isEnabled)return[];await a();let m=await z(s,{ledger:b,group:d},{tenantId:r,externalUserId:i.externalUserId?.trim()||null,email:(0,O.normalizeAuthEmail)(i.email)});return[...new Set(m.map(f=>f.groupId))].sort((f,D)=>f-D)},async isEmailAllowedByGroup(r){if(!h.isEnabled)return!1;let i=(0,O.normalizeAuthEmail)(r);if(i==="")return!1;await a();let[m]=await s.select({id:b.id}).from(b).innerJoin(l,(0,u.eq)(l.groupId,b.groupId)).innerJoin(d,(0,u.and)((0,u.eq)(d.id,b.groupId),(0,u.eq)(d.isActive,!0))).where((0,u.eq)(b.email,i));return!!m},async listAllowlistGroups(r){return(0,x.assertTenantId)(r,"listAllowlistGroups(tenantId)"),await a(),(await s.select({id:l.id,groupId:l.groupId,groupKey:d.groupKey,groupName:d.name,description:l.description}).from(l).innerJoin(d,(0,u.and)((0,u.eq)(d.id,l.groupId),(0,u.eq)(d.tenantId,r))).where((0,u.eq)(l.tenantId,r)).orderBy((0,u.asc)(d.name))).map(m=>({id:Number(m.id),type:"group",groupId:Number(m.groupId),groupKey:String(m.groupKey),groupName:String(m.groupName),...m.description?{description:String(m.description)}:{},owner:{kind:"tenant",tenantId:r},readOnly:!1}))},async addAllowlistGroup(r,i,m,f){(0,x.assertTenantId)(r,"addAllowlistGroup(tenantId)"),await a(),await s.transaction(async D=>{await T(D,r,i);let[k]=await D.select({id:n.id}).from(n).where((0,u.and)((0,u.eq)(n.groupId,i),(0,u.eq)(n.tenantId,r)));if(!k)throw new Error(`Group ${i} is locally managed; only externally-sourced groups can gate sign-in, because the decision reads the upstream member ledger.`);await D.insert(l).output().values({tenantId:r,groupId:i,description:m??null,createdAt:new Date,createdBy:f})})},async removeAllowlistGroup(r,i){(0,x.assertTenantId)(r,"removeAllowlistGroup(tenantId)"),await a(),await s.delete(l).where((0,u.and)((0,u.eq)(l.id,i),(0,u.eq)(l.tenantId,r)))},async countProjectedMembers(r,i){(0,x.assertTenantId)(r,"countProjectedMembers(tenantId)"),await a();let[m]=await s.select({n:(0,u.count)()}).from(v).innerJoin(d,(0,u.and)((0,u.eq)(d.id,v.groupId),(0,u.eq)(d.tenantId,r))).where((0,u.eq)(v.groupId,i));return Number(m?.n??0)}}}var ie=require("@aiquants/auth-core"),B=require("@aiquants/authz-core");async function Ie(t,o){let g=(0,B.assertTenantId)(o.tenantId,"promoteLedgerForUser(tenantId)");if(!Number.isInteger(o.userId)||o.userId<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] userId must be a positive integer, received ${String(o.userId)}`);let h=(0,ie.normalizeAuthEmail)(o.email),s=o.externalUserId?.trim()||null;if(s===null&&h==="")return{addedGroupIds:[],matchedLedgerIds:[]};let a=await t.findLedgerMatches({tenantId:g,externalUserId:s,email:h});if(a.length===0)return{addedGroupIds:[],matchedLedgerIds:[]};for(let n of a)(0,B.assertTenantMatch)(g,n.tenantId,"promoteLedgerForUser(findLedgerMatches row)");let p=[...new Set(a.map(n=>n.ledgerId))].sort((n,b)=>n-b),y=[...new Set(a.map(n=>n.groupId))].sort((n,b)=>n-b);return{addedGroupIds:[...await t.attachUserToGroups({tenantId:g,userId:o.userId,ledgerIds:p,groupIds:y})].sort((n,b)=>n-b),matchedLedgerIds:p}}var Y=require("@aiquants/authz-core"),R=require("drizzle-orm");var se=2100;var qe=500;function L(t,o=500){if(!Number.isInteger(o)||o<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] chunk size must be a positive integer, received ${String(o)}`);let g=[];for(let h=0;h<t.length;h+=o)g.push(t.slice(h,h+o));return g}function N(t,o,g=100){if(!Number.isInteger(o)||o<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] parametersPerItem must be a positive integer, received ${String(o)}`);if(!Number.isInteger(g)||g<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] reservedParameters must be a non-negative integer, received ${String(g)}`);let h=2100-g,s=Math.floor(h/o);if(s<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] a single item binds ${o} parameters, which exceeds the ${h} available in one statement`);return L(t,s)}var Ae=4,Se=100;function ve(t,o,g,h){let s=t,a=h.ensureConnection??(async()=>{}),p=h.now??(()=>new Date),y=o.TDGroupMemberEmail,{TMGroup:w,TDGroupMember:n}=g;return{async findLedgerMatches(b){return(0,Y.assertTenantId)(b.tenantId,"findLedgerMatches(tenantId)"),await a(),z(s,{ledger:y,group:w},b)},async attachUserToGroups({tenantId:b,userId:e,ledgerIds:l,groupIds:A}){return(0,Y.assertTenantId)(b,"attachUserToGroups(tenantId)"),await a(),l.length===0?[]:s.transaction(async d=>{let v=new Set;for(let r of L(A)){let i=await d.select({id:w.id}).from(w).where((0,R.and)((0,R.inArray)(w.id,r),(0,R.eq)(w.tenantId,b),(0,R.eq)(w.isActive,!0)));for(let m of i)v.add(Number(m.id))}let I=A.filter(r=>v.has(r));if(I.length===0)return[];let T=new Set;for(let r of L(I)){let i=await d.select({groupId:n.groupId}).from(n).where((0,R.and)((0,R.eq)(n.userId,e),(0,R.inArray)(n.groupId,r)));for(let m of i)T.add(Number(m.groupId))}let G=I.filter(r=>!T.has(r)),_=Math.max(1,2100-Se-I.length);for(let r of L(l,_))await d.update(y).set({resolvedUserId:e}).output().where((0,R.and)((0,R.inArray)(y.id,r),(0,R.inArray)(y.groupId,I)));if(G.length>0){let r=p();for(let i of N(G,Ae))await d.insert(n).output().values(i.map(m=>({groupId:m,userId:e,createdAt:r,createdBy:h.actor})))}return G})}}}var U=require("@aiquants/authz-drizzle"),c=require("drizzle-orm/mssql-core"),ae="provider",Te=["TDGroupExternalLink","TDTenantMembershipGroup","TDAllowlistGroup","TDDirectorySyncRequest","TMAllowlist"];function De(t,o){let g=(0,c.mssqlSchema)(t),h=()=>({createdAt:(0,c.datetime2)("created_at"),createdBy:(0,c.nvarchar)("created_by",{length:50}),updatedAt:(0,c.datetime2)("updated_at"),updatedBy:(0,c.nvarchar)("updated_by",{length:50})}),s=()=>({createdAt:(0,c.datetime2)("created_at"),createdBy:(0,c.nvarchar)("created_by",{length:50})}),a=g.table("TDGroupExternalLink",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}).notNull(),tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),provider:(0,c.nvarchar)(ae,{length:32}).notNull(),externalId:(0,c.nvarchar)("external_id",{length:256}).notNull(),externalKey:(0,c.nvarchar)("external_key",{length:320}).notNull(),membershipMode:(0,c.nvarchar)("membership_mode",{length:16}).notNull(),isSyncEnabled:(0,c.bit)("is_sync_enabled").notNull(),syncedAt:(0,c.datetime2)("synced_at"),syncError:(0,c.nvarchar)("sync_error",{length:1e3}),vanishedObservations:(0,c.int)("vanished_observations").notNull(),...h()},e=>[(0,c.primaryKey)({name:`${t}_TDGroupExternalLink_pk`,columns:[e.id]}),(0,c.uniqueIndex)(`${t}_TDGroupExternalLink_group_uq`).on(e.groupId),(0,c.uniqueIndex)(`${t}_TDGroupExternalLink_external_uq`).on(e.tenantId,e.provider,e.externalId),(0,c.foreignKey)({name:`${t}_TDGroupExternalLink_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),p=g.table("TDGroupMemberEmail",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}).notNull(),email:(0,c.nvarchar)("email",{length:320}).notNull(),externalUserId:(0,c.nvarchar)("external_user_id",{length:128}),resolvedUserId:(0,c.bigint)("resolved_user_id",{mode:"number"}),observedAt:(0,c.datetime2)("observed_at").notNull(),...h()},e=>[(0,c.primaryKey)({name:`${t}_TDGroupMemberEmail_pk`,columns:[e.id]}),(0,c.uniqueIndex)(`${t}_TDGroupMemberEmail_group_email_uq`).on(e.groupId,e.email),(0,c.foreignKey)({name:`${t}_TDGroupMemberEmail_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),y=g.table("TDTenantMembershipGroup",{tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}).notNull(),isBreakGlass:(0,c.bit)("is_break_glass").notNull(),...s()},e=>[(0,c.primaryKey)({name:`${t}_TDTenantMembershipGroup_pk`,columns:[e.tenantId,e.groupId]}),(0,c.foreignKey)({name:`${t}_TDTenantMembershipGroup_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),w=g.table("TDAllowlistGroup",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}).notNull(),description:(0,c.nvarchar)("description",{length:512}),...s()},e=>[(0,c.primaryKey)({name:`${t}_TDAllowlistGroup_pk`,columns:[e.id]}),(0,c.uniqueIndex)(`${t}_TDAllowlistGroup_tenant_group_uq`).on(e.tenantId,e.groupId),(0,c.foreignKey)({name:`${t}_TDAllowlistGroup_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),n=g.table("TDDirectorySyncRequest",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}),requestedBy:(0,c.nvarchar)("requested_by",{length:320}).notNull(),requestedAt:(0,c.datetime2)("requested_at").notNull(),pickedAt:(0,c.datetime2)("picked_at"),finishedAt:(0,c.datetime2)("finished_at"),result:(0,c.nvarchar)("result",{length:32}),error:(0,c.nvarchar)("error",{length:2e3}),...s()},e=>[(0,c.primaryKey)({name:`${t}_TDDirectorySyncRequest_pk`,columns:[e.id]})]),b=g.table("TMAllowlist",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),pattern:(0,c.nvarchar)("pattern",{length:256}).notNull(),type:(0,c.nvarchar)("type",{length:32}).notNull(),description:(0,c.nvarchar)("description",{length:512}),...s()},e=>[(0,c.primaryKey)({name:`${t}_TMAllowlist_pk`,columns:[e.id]}),(0,c.uniqueIndex)(`${t}_TMAllowlist_pattern_uq`).on(e.tenantId,e.pattern)]);return{TDGroupExternalLink:a,TDGroupMemberEmail:p,TDTenantMembershipGroup:y,TDAllowlistGroup:w,TDDirectorySyncRequest:n,TMAllowlist:b}}var C=require("@aiquants/auth-directory-core");var X=(t,o=20)=>t.length<=o?t.join(", "):`${t.slice(0,o).join(", ")} \u307B\u304B ${t.length-o} \u4EF6`,Q={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,o)=>`\u4E0A\u6D41\u304C ${t} \u4EF6\u306E\u30E1\u30F3\u30D0\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F\u304C\u3001\u7A81\u5408\u7D50\u679C\u306F ${o} \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,o,g)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${t})\u3002\u9023\u7D9A ${o} \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,o)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C ${o} \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 (${X(t.offendingEmails)})\u3002`;let o=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: ${o}\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: ${X(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 ${X(t.map(o=>String(o.userId)))})\u3002\u6B8B\u308A\u306E\u5909\u66F4\u306F\u9069\u7528\u6E08\u307F\u3067\u3059\u3002`,foreignProvider:(t,o)=>`\u3053\u306E\u30EA\u30F3\u30AF\u306E\u4F9B\u7D66\u5143\u306F ${t} \u3067\u3059\u304C\u3001\u5B9F\u884C\u4E2D\u306E\u540C\u671F\u306F ${o} \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 Z=["aborted","missing","vanished","upstream-failed","local-failed","foreign-provider"];function xe(t){let{directory:o,repository:g,policy:h,now:s,logger:a}=t,p=t.messages??Q;if((0,C.assertBlastRadiusPolicy)(h),!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 y(e,l){try{await g.recordFailure(e,l)}catch(A){a.error(`[auth-directory] could not record the failure for ${e.externalKey}:`,A)}}async function w(e){try{let l=await o.getGroup(e.externalId);return l===null?{kind:"missing"}:{kind:"ok",group:l,members:await o.listGroupMembers(l,e.membershipMode)}}catch(l){return{kind:"failed",error:l instanceof Error?l:new Error(String(l))}}}async function n(e){let l=await g.recordVanishedObservation(e,p.groupMissing(e.externalKey,e.vanishedObservations+1,t.vanishedThreshold));return l<t.vanishedThreshold?(a.warn(`[auth-directory] ${e.externalKey} missing upstream (${l}/${t.vanishedThreshold})`),{kind:"missing",link:e,observations:l}):(await g.markGroupInactive(e),await y(e,p.groupVanished(e.externalKey,l)),a.warn(`[auth-directory] ${e.externalKey} deactivated after ${l} consecutive absences`),{kind:"vanished",link:e})}async function b(e){if(e.provider!==t.provider)return await y(e,p.foreignProvider(e.provider,t.provider)),a.warn(`[auth-directory] skipping ${e.externalKey}: belongs to provider ${e.provider}`),{kind:"foreign-provider",link:e};let l=await w(e);if(l.kind==="missing")return n(e);if(l.kind==="failed")return await y(e,p.upstreamUnreadable(l.error.message)),a.error(`[auth-directory] upstream read failed for ${e.externalKey}:`,l.error),{kind:"upstream-failed",link:e,error:l.error};try{let[A,d]=await Promise.all([g.loadGroupSnapshot(e),g.resolveMembers(l.members)]);if(d.length!==l.members.length){let _=p.resolverIncomplete(l.members.length,d.length);return await y(e,_),a.error(`[auth-directory] ${_}`),{kind:"local-failed",link:e,error:new Error(_)}}let v=(0,C.reconcile)(A,d,h);if(v.aborted)return await y(e,p.planRefused(v.aborted)),a.warn(`[auth-directory] plan refused for ${e.externalKey}: ${v.aborted.reason}`),{kind:"aborted",link:e,plan:v};let I=v.ledgerUpserts.length>0||v.ledgerDeletes.length>0||v.projectionAdds.length>0||v.projectionRemoves.length>0,T=s(),G={refusals:[]};return I&&(G=await g.applyPlan(e,v,T)),await g.recordSuccess(e,l.group,T),G.refusals.length>0&&(await y(e,p.removalsRefused(G.refusals)),a.warn(`[auth-directory] ${G.refusals.length} removal(s) refused for ${e.externalKey}`)),v.unresolvedEmails.length>0&&a.info(`[auth-directory] ${e.externalKey}: ${v.unresolvedEmails.length} upstream member(s) have no local user yet`),I?{kind:"applied",link:e,plan:v}:{kind:"unchanged",link:e}}catch(A){let d=A instanceof Error?A:new Error(String(A));return await y(e,p.localWriteFailed(d.message)),a.error(`[auth-directory] local write failed for ${e.externalKey}:`,d),{kind:"local-failed",link:e,error:d}}}return{syncOne:b,async run(e={}){let l=await g.listSyncableLinks(e),A=[];for(let v of l)try{A.push(await b(v))}catch(I){let T=I instanceof Error?I:new Error(String(I));a.error(`[auth-directory] ${v.externalKey} ended abnormally:`,T),A.push({kind:"local-failed",link:v,error:T})}let d=A.filter(v=>Z.includes(v.kind)).length;return a.info(`[auth-directory] run finished: ${A.length} link(s), ${d} unhealthy`),{outcomes:A,unhealthyCount:d}}}}var de=require("@aiquants/authz-core"),P=require("drizzle-orm"),ee=2e3;function ke(t,o,g){let h=t,s=g.ensureConnection??(async()=>{}),a=o.TDDirectorySyncRequest,p=g.maxErrorLength??ee;if(!Number.isInteger(p)||p<1||p>ee)throw new TypeError(`[@aiquants/auth-directory-drizzle] maxErrorLength must be an integer within 1..${ee}, received ${String(g.maxErrorLength)}`);return{async claim(){await s();let y=await h.select({id:a.id}).from(a).where((0,P.isNull)(a.pickedAt)).orderBy((0,P.asc)(a.id));for(let w of y){let b=(await h.update(a).set({pickedAt:g.now()}).output().where((0,P.and)((0,P.eq)(a.id,Number(w.id)),(0,P.isNull)(a.pickedAt))))?.[0];if(!b)continue;let e=String(b.tenant_id??b.tenantId??""),l=b.group_id??b.groupId??null;return{id:Number(b.id),tenantId:(0,de.assertTenantId)(e,"claim(row.tenantId)"),groupId:l===null?null:Number(l),requestedBy:String(b.requested_by??b.requestedBy??"")}}return null},async finish(y,w){await s();let n=w.error?w.error.slice(0,p):null;await h.update(a).set({finishedAt:g.now(),result:w.result,error:n}).output().where((0,P.eq)(a.id,y))},async listStranded(y){return await s(),(await h.select({id:a.id,pickedAt:a.pickedAt}).from(a).where((0,P.isNull)(a.finishedAt)).orderBy((0,P.asc)(a.id))).filter(n=>n.pickedAt!==null&&new Date(n.pickedAt)<y).map(n=>Number(n.id))}}}var re=require("@aiquants/auth-core"),q=require("@aiquants/authz-core"),S=require("drizzle-orm");var Ge=7,Ee=4;function Me(t,o,g,h){let s=t,a=h.ensureConnection??(async()=>{}),{TDGroupExternalLink:p,TDGroupMemberEmail:y}=o,{TMGroup:w,TDGroupMember:n}=g,b=h.actor;return{async listSyncableLinks(e){await a();let l=[(0,S.eq)(p.isSyncEnabled,!0)];return e.tenantId!==void 0&&l.push((0,S.eq)(p.tenantId,(0,q.assertTenantId)(e.tenantId,"listSyncableLinks(tenantId)"))),e.groupId!==void 0&&l.push((0,S.eq)(p.groupId,e.groupId)),(await s.select({linkId:p.id,groupId:p.groupId,linkTenantId:p.tenantId,groupTenantId:w.tenantId,groupKey:w.groupKey,isGroupActive:w.isActive,provider:p.provider,externalId:p.externalId,externalKey:p.externalKey,membershipMode:p.membershipMode,vanishedObservations:p.vanishedObservations}).from(p).innerJoin(w,(0,S.eq)(w.id,p.groupId)).where((0,S.and)(...l))).map(d=>((0,q.assertTenantMatch)(String(d.groupTenantId),String(d.linkTenantId),"listSyncableLinks(link.tenantId vs TMGroup.tenant_id)"),{linkId:Number(d.linkId),groupId:Number(d.groupId),groupKey:String(d.groupKey),tenantId:String(d.groupTenantId),provider:String(d.provider),externalId:String(d.externalId),externalKey:String(d.externalKey),membershipMode:K(String(d.membershipMode)),isGroupActive:!!d.isGroupActive,vanishedObservations:Number(d.vanishedObservations??0)}))},async loadGroupSnapshot(e){await a();let[l,A]=await Promise.all([s.select({email:y.email,externalUserId:y.externalUserId,resolvedUserId:y.resolvedUserId}).from(y).where((0,S.eq)(y.groupId,e.groupId)),s.select({userId:n.userId}).from(n).where((0,S.eq)(n.groupId,e.groupId))]);return{ledger:l.map(d=>({email:String(d.email),...d.externalUserId?{externalUserId:String(d.externalUserId)}:{},resolvedUserId:d.resolvedUserId===null?null:Number(d.resolvedUserId)})),projectedUserIds:A.map(d=>Number(d.userId))}},resolveMembers(e){return h.memberResolver.resolve(e)},async applyPlan(e,l,A){(0,q.assertTenantId)(e.tenantId,"applyPlan(link.tenantId)"),await a(),(l.ledgerUpserts.length>0||l.projectionAdds.length>0)&&await s.transaction(async I=>{let T=l.ledgerUpserts.map(r=>({...r,email:(0,re.normalizeAuthEmail)(r.email)})),G=new Map;for(let r of L(T.map(i=>i.email))){let i=await I.select({id:y.id,email:y.email}).from(y).where((0,S.and)((0,S.eq)(y.groupId,e.groupId),(0,S.inArray)(y.email,r)));for(let m of i)G.set(String(m.email),Number(m.id))}let _=T.filter(r=>!G.has(r.email));for(let r of N(_,Ge))await I.insert(y).output().values(r.map(i=>({groupId:e.groupId,email:i.email,externalUserId:i.externalUserId??null,resolvedUserId:i.resolvedUserId,observedAt:A,createdAt:A,createdBy:b})));for(let r of T){let i=G.get(r.email);i!==void 0&&await I.update(y).set({externalUserId:r.externalUserId??null,resolvedUserId:r.resolvedUserId,observedAt:A,updatedAt:A,updatedBy:b}).output().where((0,S.eq)(y.id,i))}for(let r of N(l.projectionAdds,Ee)){let i=new Set((await I.select({userId:n.userId}).from(n).where((0,S.and)((0,S.eq)(n.groupId,e.groupId),(0,S.inArray)(n.userId,r)))).map(f=>Number(f.userId))),m=r.filter(f=>!i.has(f));m.length>0&&await I.insert(n).output().values(m.map(f=>({groupId:e.groupId,userId:f,createdAt:A,createdBy:b})))}});let d=[];for(let I of l.projectionRemoves)try{await h.lockoutGuard.guardedWrite(e.tenantId,{removeGroupMembership:{groupId:e.groupId,userId:I}},"remove-group-member",T=>T.delete(n).where((0,S.and)((0,S.eq)(n.groupId,e.groupId),(0,S.eq)(n.userId,I))))}catch(T){d.push({userId:I,applied:!1,refusal:T instanceof Error?T.message:String(T)})}let v=d.map(I=>I.userId);return l.ledgerDeletes.length>0&&await s.transaction(async I=>{for(let T of L(l.ledgerDeletes)){let G=v.length>0?(0,S.or)((0,S.isNull)(y.resolvedUserId),(0,S.notInArray)(y.resolvedUserId,v)):void 0;await I.delete(y).where((0,S.and)((0,S.eq)(y.groupId,e.groupId),(0,S.inArray)(y.email,T),...G?[G]:[]))}}),{refusals:d}},async recordSuccess(e,l,A){await a(),await s.transaction(async d=>{await d.update(p).set({syncedAt:A,syncError:null,vanishedObservations:0,externalId:l.externalId,externalKey:(0,re.normalizeAuthEmail)(l.externalKey),updatedAt:A,updatedBy:b}).output().where((0,S.eq)(p.id,e.linkId)),e.isGroupActive||await d.update(w).set({isActive:!0,updatedAt:A,updatedBy:b}).output().where((0,S.and)((0,S.eq)(w.id,e.groupId),(0,S.eq)(w.tenantId,e.tenantId)))})},async recordFailure(e,l){await a(),await s.update(p).set({syncError:l.slice(0,1e3),updatedAt:new Date,updatedBy:b}).output().where((0,S.eq)(p.id,e.linkId))},async recordVanishedObservation(e,l){await a();let A=e.vanishedObservations+1;return await s.update(p).set({vanishedObservations:A,syncError:l.slice(0,1e3),updatedAt:new Date,updatedBy:b}).output().where((0,S.eq)(p.id,e.linkId)),A},async markGroupInactive(e){await a(),await s.update(w).set({isActive:!1,updatedAt:new Date,updatedBy:b}).output().where((0,S.and)((0,S.eq)(w.id,e.groupId),(0,S.eq)(w.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
|