@aiquants/auth-directory-drizzle 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +6 -3
- package/dist/index.d.ts +6 -3
- 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 +4 -4
package/dist/index.d.mts
CHANGED
|
@@ -2463,11 +2463,14 @@ declare function createSyncRequestQueue(dbUnknown: unknown, tables: AuthDirector
|
|
|
2463
2463
|
/**
|
|
2464
2464
|
* Records how a claimed request ended. 取得済みの要求がどう終わったかを記録する処理。
|
|
2465
2465
|
*
|
|
2466
|
+
* ⚠️ 未完了の行にしか書かない。既に結末が記録されている行は **0 行更新** になるので、
|
|
2467
|
+
* 「書けたかどうか」を返す。返さないと、呼び出し側は閉じていない行を閉じたと報告する。
|
|
2468
|
+
*
|
|
2466
2469
|
* @param id - The claimed request id. 取得した要求の ID。
|
|
2467
2470
|
* @param outcome - Result and optional error text. 結果と (あれば) エラー文。
|
|
2468
|
-
* @returns
|
|
2471
|
+
* @returns True when this call recorded the outcome. この呼び出しが結末を記録した場合に true。
|
|
2469
2472
|
*/
|
|
2470
|
-
finish(id: number, outcome: SyncRequestResult): Promise<
|
|
2473
|
+
finish(id: number, outcome: SyncRequestResult): Promise<boolean>;
|
|
2471
2474
|
/**
|
|
2472
2475
|
* Lists requests that are not progressing. 進んでいない要求の一覧。
|
|
2473
2476
|
*
|
|
@@ -2499,7 +2502,7 @@ declare function createSyncRequestQueue(dbUnknown: unknown, tables: AuthDirector
|
|
|
2499
2502
|
*
|
|
2500
2503
|
* @param olderThan - Requests picked before this are considered abandoned.
|
|
2501
2504
|
* これより前に掴まれた要求を放棄と見なす締切時刻。
|
|
2502
|
-
* @returns The ids closed.
|
|
2505
|
+
* @returns The ids this call actually closed. この呼び出しが実際に閉じた要求の ID。
|
|
2503
2506
|
*/
|
|
2504
2507
|
abandonStranded(olderThan: Date): Promise<number[]>;
|
|
2505
2508
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -2463,11 +2463,14 @@ declare function createSyncRequestQueue(dbUnknown: unknown, tables: AuthDirector
|
|
|
2463
2463
|
/**
|
|
2464
2464
|
* Records how a claimed request ended. 取得済みの要求がどう終わったかを記録する処理。
|
|
2465
2465
|
*
|
|
2466
|
+
* ⚠️ 未完了の行にしか書かない。既に結末が記録されている行は **0 行更新** になるので、
|
|
2467
|
+
* 「書けたかどうか」を返す。返さないと、呼び出し側は閉じていない行を閉じたと報告する。
|
|
2468
|
+
*
|
|
2466
2469
|
* @param id - The claimed request id. 取得した要求の ID。
|
|
2467
2470
|
* @param outcome - Result and optional error text. 結果と (あれば) エラー文。
|
|
2468
|
-
* @returns
|
|
2471
|
+
* @returns True when this call recorded the outcome. この呼び出しが結末を記録した場合に true。
|
|
2469
2472
|
*/
|
|
2470
|
-
finish(id: number, outcome: SyncRequestResult): Promise<
|
|
2473
|
+
finish(id: number, outcome: SyncRequestResult): Promise<boolean>;
|
|
2471
2474
|
/**
|
|
2472
2475
|
* Lists requests that are not progressing. 進んでいない要求の一覧。
|
|
2473
2476
|
*
|
|
@@ -2499,7 +2502,7 @@ declare function createSyncRequestQueue(dbUnknown: unknown, tables: AuthDirector
|
|
|
2499
2502
|
*
|
|
2500
2503
|
* @param olderThan - Requests picked before this are considered abandoned.
|
|
2501
2504
|
* これより前に掴まれた要求を放棄と見なす締切時刻。
|
|
2502
|
-
* @returns The ids closed.
|
|
2505
|
+
* @returns The ids this call actually closed. この呼び出しが実際に閉じた要求の ID。
|
|
2503
2506
|
*/
|
|
2504
2507
|
abandonStranded(olderThan: Date): Promise<number[]>;
|
|
2505
2508
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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});
|
|
1
|
+
"use strict";var ie=Object.defineProperty;var De=Object.getOwnPropertyDescriptor;var xe=Object.getOwnPropertyNames;var ke=Object.prototype.hasOwnProperty;var Re=(e,n)=>{for(var m in n)ie(e,m,{get:n[m],enumerable:!0})},Ee=(e,n,m,d)=>{if(n&&typeof n=="object"||typeof n=="function")for(let u of xe(n))!ke.call(e,u)&&u!==m&&ie(e,u,{get:()=>n[u],enumerable:!(d=De(n,u))||d.enumerable});return e};var Me=e=>Ee(ie({},"__esModule",{value:!0}),e);var Qe={};Re(Qe,{AUTH_DIRECTORY_PROVIDER_COLUMN:()=>te,AUTH_DIRECTORY_TENANT_SCOPED_TABLES:()=>Fe,MAX_IN_LIST:()=>ye,MAX_PARAMETERS:()=>V,MEMBERSHIP_MODES:()=>se,NEWLY_UNHEALTHY_SYNC_OUTCOMES:()=>ne,RESERVED_PARAMETERS:()=>me,STRANDED_REASON:()=>ve,UNHEALTHY_SYNC_OUTCOMES:()=>ce,assertGroupMayBeLinked:()=>Ke,assertMembershipMode:()=>z,chunk:()=>L,chunkByParameters:()=>N,classifySyncFailure:()=>W,createDirectoryCatalogReader:()=>Pe,createDirectoryCatalogWriter:()=>_e,createDirectoryLinkStore:()=>qe,createDirectorySync:()=>We,createDirectorySyncRepository:()=>Xe,createPromotionRepository:()=>Be,createSyncRequestQueue:()=>He,defaultExternalGroupGuardMessage:()=>Le,defaultSyncMessages:()=>le,defineAuthDirectorySchema:()=>je,findLedgerRowsForIdentity:()=>j,promoteLedgerForUser:()=>Oe,toInstant:()=>K,withExternalGroupGuards:()=>$e});module.exports=Me(Qe);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 V=2100,me=100,ye=500;function L(e,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 m=[];for(let d=0;d<e.length;d+=n)m.push(e.slice(d,d+n));return m}function N(e,n,m=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(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/n);if(u<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] a single item binds ${n} parameters, which exceeds the ${d} available in one statement`);return L(e,u)}var Ge=10,$={tenantId:64,provider:32,externalId:256,externalKey:320,name:256,description:1e3,actor:50},ge=2147483647;function Ce(e){if(e===void 0||!Number.isFinite(e))return null;let n=Math.trunc(e);return n<0?null:n>ge?ge:n}function B(e,n,m){let d=e.trim();if(d==="")throw new TypeError(`[@aiquants/auth-directory-drizzle] ${m} must not be blank`);if(d.length>n)throw new TypeError(`[@aiquants/auth-directory-drizzle] ${m} exceeds its column length (${n}); truncating it would change which rows it owns`);return d}function _e(e,n,m){let d=e,u=m.ensureConnection??(async()=>{}),s=n.TDDirectoryCatalog,b=n.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"),t=B(a,$.provider,"provider"),i=B(m.actor,$.actor,"actor"),l=m.now(),I=f(g.map(w=>({tenantId:r,provider:t,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:Ce(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,t)));for(let R of N(I,Ge))await w.insert(s).values(R);await w.delete(b).where((0,_.and)((0,_.eq)(b.tenantId,r),(0,_.eq)(b.provider,t))),await w.insert(b).values([{tenantId:r,provider:t,observedAt:l,entryCount:I.length,createdAt:l,createdBy:i,updatedAt:l,updatedBy:i}])}),I.length}}}function Pe(e,n,m={}){let d=e,u=m.ensureConnection??(async()=>{}),s=n.TDDirectoryCatalog,b=n.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)),t=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:t,observedAt:null};if(Number(i.entryCount)!==t.length)throw new Error(`[@aiquants/auth-directory-drizzle] catalog is inconsistent for (${a}, ${g}): the observation records ${i.entryCount} entries but ${t.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:t,observedAt:l}}}}var he=require("@aiquants/authz-core"),Le=(e,n)=>`\u5916\u90E8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u9023\u643A\u30B0\u30EB\u30FC\u30D7 (${n}) \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,n,m,d){return new Set(e.filter(u=>n.has(u.roleId)&&u.appKey===m&&u.resourceKey===d).map(u=>u.action))}function X(e,n){return new Set(e.filter(m=>m.groupId===n).map(m=>m.roleId))}var F=e=>he.AUTHZ_ACTIONS.every(n=>e.has(n)),Z=(e,n)=>e.find(m=>m.roleId===n)?.roleKey??`#${n}`;function Q(e,n,m,d){let u=[...n].find(b=>F(U(e,new Set([b]),m,d)));return u!==void 0?Z(e,u):[...n].filter(b=>U(e,new Set([b]),m,d).size>0).map(b=>Z(e,b)).join(" + ")}function $e(e,n){return be(e,n)}function be(e,n){let m=e;return{...e,withTransaction:(d,u)=>m.withTransaction((s,b)=>d(be(s,n),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,n.adminAppKey,n.adminResourceKey))){let r=await n.linkLookup.externalGroupKey(d,u,S);if(r!==null)throw new Error(n.message(Q(a,g,n.adminAppKey,n.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===n.adminAppKey&&i?.resourceKey===n.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),R=U(g.filter(k=>k.id!==u),w,n.adminAppKey,n.adminResourceKey);if(w.has(r.roleId)&&R.add(f),!F(R))continue;let T=await n.linkLookup.externalGroupKey(d,I,a);if(T!==null)throw new Error(n.message(Q(g,w,n.adminAppKey,n.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===n.adminAppKey&&a?.resourceKey===n.adminResourceKey){let g=await b.listGrants(d),r=await b.listGroupRoles(d);for(let t of new Set(r.filter(i=>i.roleId===u.roleId).map(i=>i.groupId))){let i=U(g,X(r,t),n.adminAppKey,n.adminResourceKey);if(i.add(u.action),!F(i))continue;let l=await n.linkLookup.externalGroupKey(d,t,f);if(l!==null)throw new Error(n.message(Q(g,X(r,t),n.adminAppKey,n.adminResourceKey)||Z(g,u.roleId),l))}}await b.createGrant(d,u,s)})}}}async function Ke(e,n,m,d){let u=(await e.listGroupRoles(n)).filter(S=>S.groupId===m);if(u.length===0)return;let s=await e.listGrants(n),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,n,m){let{ledger:d,group:u}=n,{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,R)=>w.ledgerId-R.ledgerId)},r=b===null?[]:await a((0,q.eq)(d.externalUserId,b));if(f==="")return g(r);let t=await a((0,q.eq)(d.email,f)),i=l=>l.externalUserId!==null&&l.externalUserId!==b;return g([...r,...t.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 Ne(e){let n=typeof e=="object"&&e!==null&&"number"in e?e.number:void 0;return n===2601||n===2627}function qe(e,n,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:t,TDDirectorySyncRequest:i}=n,{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 R(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 Y=>{let E=Y;await R(E,o,y),await w(E,o,y),await E.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 R(h,o,y),await h.delete(g).where((0,c.eq)(g.groupId,y)),await h.delete(t).where((0,c.and)((0,c.eq)(t.groupId,y),(0,c.eq)(t.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 R(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(!Ne(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(E=>!!E.isSyncEnabled),D=v.map(E=>E.syncedAt?K(E.syncedAt).getTime():null),x=D.length>0&&D.every(E=>E!==null)?Math.min(...D):null,Y=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:Y,pausedGroupCount:y.length-v.length,stalenessThresholdSec:d.stalenessThresholdSec,erroredGroupIds:y.filter(E=>!!E.syncError).map(E=>Number(E.groupId)).sort((E,Te)=>E-Te),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 R(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(E=>Number(E.groupId)!==y).some(E=>!!E.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(t,(0,c.eq)(t.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:t.id,groupId:t.groupId,groupKey:l.groupKey,groupName:l.name,description:t.description}).from(t).innerJoin(l,(0,c.and)((0,c.eq)(l.id,t.groupId),(0,c.eq)(l.tenantId,o))).where((0,c.eq)(t.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 R(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(t).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(t).where((0,c.and)((0,c.eq)(t.id,y),(0,c.eq)(t.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 Oe(e,n){let m=(0,re.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 d=(0,we.normalizeAuthEmail)(n.email),u=n.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:n.userId,ledgerIds:b,groupIds:f})].sort((a,g)=>a-g),matchedLedgerIds:b}}var ue=require("@aiquants/authz-core"),P=require("drizzle-orm");var Ue=4,ze=100;function Be(e,n,m,d){let u=e,s=d.ensureConnection??(async()=>{}),b=d.now??(()=>new Date),f=n.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:t,groupIds:i}){return(0,ue.assertTenantId)(g,"attachUserToGroups(tenantId)"),await s(),t.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 R=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)R.add(Number(h.groupId))}let T=w.filter(o=>!R.has(o)),k=Math.max(1,2100-ze-w.length);for(let o of L(t,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,Ue))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",Fe=["TDGroupExternalLink","TDTenantMembershipGroup","TDAllowlistGroup","TDDirectorySyncRequest","TDDirectoryCatalog","TMDirectoryCatalogObservation","TMAllowlist"];function je(e,n){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:[n.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:[n.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:[n.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:[n.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)]),t=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:t,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 n=typeof e=="object"&&e!==null&&"status"in e?e.status:void 0;return typeof n!="number"?"unknown":n===401||n===403?"denied":n===429||n===408?"rateLimited":n>=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,n)=>`\u4E0A\u6D41\u304C ${e} \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:(e,n,m)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${e})\u3002\u9023\u7D9A ${n} \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,n)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C ${n} \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 n=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: ${n}\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(n=>de[n.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(n=>n.userId).join(", ")})\u3002\u6B8B\u308A\u306E\u5909\u66F4\u306F\u9069\u7528\u6E08\u307F\u3067\u3059\u3002`,foreignProvider:(e,n)=>`\u3053\u306E\u30EA\u30F3\u30AF\u306E\u4F9B\u7D66\u5143\u306F ${e} \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 ne=["aborted","missing","vanished","upstream-failed","local-failed","foreign-provider","not-converged"],ce=[...ne,"already-vanished"];function We(e){let{directory:n,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,t){try{await m.recordFailure(r,t)}catch(i){s.error(`[auth-directory] could not record the failure for ${r.externalKey}:`,i)}}async function S(r){try{let t=await n.getGroup(r.externalId);return t===null?{kind:"missing"}:{kind:"ok",group:t,members:await n.listGroupMembers(t,r.membershipMode)}}catch(t){return{kind:"failed",error:t instanceof Error?t:new Error(String(t))}}}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 t=await m.recordVanishedObservation(r,b.groupMissing(r.externalKey,r.vanishedObservations+1,e.vanishedThreshold));return t<e.vanishedThreshold?(s.warn(`[auth-directory] ${r.externalKey} missing upstream (${t}/${e.vanishedThreshold})`),{kind:"missing",link:r,observations:t}):(await m.markGroupInactive(r),await f(r,b.groupVanished(r.externalKey,t)),s.warn(`[auth-directory] ${r.externalKey} deactivated after ${t} 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 t=await S(r);if(t.kind==="missing")return a(r);if(t.kind==="failed")return await f(r,b.upstreamUnreadable(W(t.error))),s.error(`[auth-directory] upstream read failed for ${r.externalKey}:`,t.error),{kind:"upstream-failed",link:r,error:t.error};try{await m.resolveExternalIdentity(r,t.group);let[i,l]=await Promise.all([m.loadGroupSnapshot(r),m.resolveMembers(t.members)]);if(l.length!==t.members.length){let k=b.resolverIncomplete(t.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,R=u(),T={refusals:[],failures:[]};return w&&(T=await m.applyPlan(r,I,R)),await m.recordSuccess(r,t.group,R),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 t=await m.listSyncableLinks(r),i=[];for(let w of t)try{i.push(await g(w))}catch(R){let T=R instanceof Error?R:new Error(String(R));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 He(e,n,m){let d=e,u=m.ensureConnection??(async()=>{}),s=n.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 t=(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(!t)continue;if(t.requestedBy===void 0||t.requestedBy===null)throw new TypeError(`[@aiquants/auth-directory-drizzle] the driver returned a row without requestedBy for request ${String(t.id)}`);let i=t.groupId??null;return{id:Number(t.id),tenantId:b,groupId:i===null?null:Number(i),requestedBy:String(t.requestedBy)}}return null},async finish(a,g){await u();let r=g.error?g.error.slice(0,f):null;return!!(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))))?.length},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=t=>{let i=K(t);return Number.isNaN(i.getTime())||i<a};return{stranded:g.filter(t=>t.pickedAt!==null&&r(t.pickedAt)).map(t=>Number(t.id)),unclaimed:g.filter(t=>t.pickedAt===null&&r(t.requestedAt)).map(t=>Number(t.id))}},async abandonStranded(a){let{stranded:g}=await S.listStranded(a),r=[];for(let t of g)try{await S.finish(t,{result:"failed",error:ve})&&r.push(t)}catch(i){m.onCloseFailed?.(t,i)}return r}};return S}var H=require("@aiquants/auth-core"),J=require("@aiquants/authz-core"),A=require("drizzle-orm");var Je=7,Ye=4,Ae=1e3;function Ve(e){if(!(e instanceof Error))return!1;let n=e;return n.number===void 0&&n.code===void 0&&e.name==="Error"}function Xe(e,n,m,d){let u=e,s=d.ensureConnection??(async()=>{}),b=d.now??(()=>new Date),{TDGroupExternalLink:f,TDGroupMemberEmail:S}=n,{TMGroup:a,TDGroupMember:g}=m,r=d.actor;return{async listSyncableLinks(t){await s();let i=(0,J.assertTenantId)(t.tenantId,"listSyncableLinks(tenantId)"),l=[(0,A.eq)(f.isSyncEnabled,!0),(0,A.eq)(f.tenantId,i)];return t.groupId!==void 0&&l.push((0,A.eq)(f.groupId,t.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(t){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,t.groupId)),u.select({userId:g.userId}).from(g).where((0,A.eq)(g.groupId,t.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(t){return d.memberResolver.resolve(t)},async applyPlan(t,i,l){(0,J.assertTenantId)(t.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,t.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,Je))await T.insert(S).output().values(h.map(v=>({groupId:t.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,Ye)){let v=new Set((await T.select({userId:g.userId}).from(g).where((0,A.and)((0,A.eq)(g.groupId,t.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:t.groupId,userId:x,createdAt:l,createdBy:r})))}});let I=[],w=[];for(let T of i.projectionRemoves)try{await d.lockoutGuard.guardedWrite(t.tenantId,{removeGroupMembership:{groupId:t.groupId,userId:T}},"remove-group-member",k=>k.delete(g).where((0,A.and)((0,A.eq)(g.groupId,t.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 R=I.map(T=>T.userId);if(i.ledgerDeletes.length>0){let T=Math.max(1,1999-R.length);await u.transaction(async k=>{for(let o of L(i.ledgerDeletes,Math.min(500,T))){let y=R.length>0?(0,A.or)((0,A.isNull)(S.resolvedUserId),(0,A.notInArray)(S.resolvedUserId,R)):void 0;await k.delete(S).where((0,A.and)((0,A.eq)(S.groupId,t.groupId),(0,A.inArray)(S.email,o),...y?[y]:[]))}})}return{refusals:I,failures:w}},async resolveExternalIdentity(t,i){await s(),!(t.externalId===i.externalId&&t.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,t.linkId),(0,A.eq)(f.tenantId,t.tenantId)))},async recordSuccess(t,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,t.linkId),(0,A.eq)(f.tenantId,t.tenantId))),t.isGroupActive||await I.update(a).set({isActive:!0,updatedAt:l,updatedBy:r}).output().where((0,A.and)((0,A.eq)(a.id,t.groupId),(0,A.eq)(a.tenantId,t.tenantId)))})},async recordFailure(t,i){await s(),await u.update(f).set({syncError:i.slice(0,Ae),updatedAt:b(),updatedBy:r}).output().where((0,A.and)((0,A.eq)(f.id,t.linkId),(0,A.eq)(f.tenantId,t.tenantId)))},async recordVanishedObservation(t,i){await s();let l=t.vanishedObservations+1;return await u.update(f).set({vanishedObservations:l,syncError:i.slice(0,Ae),updatedAt:b(),updatedBy:r}).output().where((0,A.and)((0,A.eq)(f.id,t.linkId),(0,A.eq)(f.tenantId,t.tenantId))),l},async markGroupInactive(t){await s(),await u.update(a).set({isActive:!1,updatedAt:b(),updatedBy:r}).output().where((0,A.and)((0,A.eq)(a.id,t.groupId),(0,A.eq)(a.tenantId,t.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
|