@aiquants/auth-directory-drizzle 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +28 -2
- package/dist/index.d.ts +28 -2
- 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
|
@@ -1113,8 +1113,12 @@ type LedgerIdentityTables = {
|
|
|
1113
1113
|
* Finds every ledger row that belongs to the identity, within one tenant.
|
|
1114
1114
|
* 1 テナント内で、その identity に属する台帳行をすべて探す処理。
|
|
1115
1115
|
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1116
|
+
* 上流 ID の一致は無条件に本人。アドレスの一致は、その行が **別の** 上流 ID に紐付いていない
|
|
1117
|
+
* ときだけ本人である。単純な `OR` にすると後者の条件が消え、退職者のアドレスを再利用した
|
|
1118
|
+
* 新入社員が前任者の所属をそのまま継承する。
|
|
1119
|
+
*
|
|
1120
|
+
* ⚠️ この優先順位は **行ごと** に適用する。「ID で当たったらアドレスは見ない」という打ち切りは
|
|
1121
|
+
* 誤りで、同じ人物の行が ID 付きと ID 無しに混在すると ID 無しの行が丸ごと落ちる。
|
|
1118
1122
|
*
|
|
1119
1123
|
* @param db - Connected database surface. 接続済みの DB 面。
|
|
1120
1124
|
* @param tables - The ledger and its parent group table. 台帳と親グループ表。
|
|
@@ -1169,6 +1173,18 @@ type DirectoryLinkStoreOptions = {
|
|
|
1169
1173
|
stalenessThresholdSec: number;
|
|
1170
1174
|
/** False when directory integration is not wired for this deployment. 未結線なら false。 */
|
|
1171
1175
|
isEnabled: boolean;
|
|
1176
|
+
/**
|
|
1177
|
+
* Milliseconds to reuse a loaded tenant-membership policy. 帰属方針を再利用するミリ秒。
|
|
1178
|
+
*
|
|
1179
|
+
* 既定は 0 (毎回引き直す)。帰属証明は **権限を 1 件も読む前に毎リクエスト走る** ため、
|
|
1180
|
+
* 証明グループを 1 つも宣言していない配備でも 3 表の結合が 1 往復増える。
|
|
1181
|
+
*
|
|
1182
|
+
* ⚠️ 既定を非 0 にしない。認可の判断材料を、頼まれてもいないのに黙って古くするライブラリは
|
|
1183
|
+
* 信用できない。有効化は配備側が「どれだけ古くてよいか」を決めて明示する。
|
|
1184
|
+
* 本ストア自身の書き込み (証明グループの増減・連携の作成解除) は自動で破棄するため、
|
|
1185
|
+
* 遅れが出るのは **記憶域を直接編集した場合だけ** である。
|
|
1186
|
+
*/
|
|
1187
|
+
policyCacheTtlMs?: number;
|
|
1172
1188
|
};
|
|
1173
1189
|
/** One external link row as the admin surface sees it. 管理面が見る外部リンク行。 */
|
|
1174
1190
|
type DirectoryLinkRow = AuthGroupExternalLink & {
|
|
@@ -1437,6 +1453,16 @@ type PromotionRepositoryOptions = {
|
|
|
1437
1453
|
/** Injected clock — tests must not depend on wall time. 注入時計 (実時刻に依存させない)。 */
|
|
1438
1454
|
now?: () => Date;
|
|
1439
1455
|
};
|
|
1456
|
+
/**
|
|
1457
|
+
* Builds the promotion repository over the directory ledger and the authz membership table.
|
|
1458
|
+
* ディレクトリ台帳と認可の所属表に対して、昇格リポジトリを構築する処理。
|
|
1459
|
+
*
|
|
1460
|
+
* @param dbUnknown - Drizzle database instance. drizzle のデータベースインスタンス。
|
|
1461
|
+
* @param tables - Directory tables (owns the ledger). ディレクトリ表 (台帳の所有者)。
|
|
1462
|
+
* @param authzTables - Authorization tables (owns groups and membership). 認可表 (グループと所属の所有者)。
|
|
1463
|
+
* @param opts - Connection, actor and clock. 接続・実行者・時計。
|
|
1464
|
+
* @returns A repository consumable by `promoteLedgerForUser`. `promoteLedgerForUser` が使うリポジトリ。
|
|
1465
|
+
*/
|
|
1440
1466
|
declare function createPromotionRepository(dbUnknown: unknown, tables: AuthDirectoryTables, authzTables: AuthzTables, opts: PromotionRepositoryOptions): PromotionRepository;
|
|
1441
1467
|
|
|
1442
1468
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1113,8 +1113,12 @@ type LedgerIdentityTables = {
|
|
|
1113
1113
|
* Finds every ledger row that belongs to the identity, within one tenant.
|
|
1114
1114
|
* 1 テナント内で、その identity に属する台帳行をすべて探す処理。
|
|
1115
1115
|
*
|
|
1116
|
-
*
|
|
1117
|
-
*
|
|
1116
|
+
* 上流 ID の一致は無条件に本人。アドレスの一致は、その行が **別の** 上流 ID に紐付いていない
|
|
1117
|
+
* ときだけ本人である。単純な `OR` にすると後者の条件が消え、退職者のアドレスを再利用した
|
|
1118
|
+
* 新入社員が前任者の所属をそのまま継承する。
|
|
1119
|
+
*
|
|
1120
|
+
* ⚠️ この優先順位は **行ごと** に適用する。「ID で当たったらアドレスは見ない」という打ち切りは
|
|
1121
|
+
* 誤りで、同じ人物の行が ID 付きと ID 無しに混在すると ID 無しの行が丸ごと落ちる。
|
|
1118
1122
|
*
|
|
1119
1123
|
* @param db - Connected database surface. 接続済みの DB 面。
|
|
1120
1124
|
* @param tables - The ledger and its parent group table. 台帳と親グループ表。
|
|
@@ -1169,6 +1173,18 @@ type DirectoryLinkStoreOptions = {
|
|
|
1169
1173
|
stalenessThresholdSec: number;
|
|
1170
1174
|
/** False when directory integration is not wired for this deployment. 未結線なら false。 */
|
|
1171
1175
|
isEnabled: boolean;
|
|
1176
|
+
/**
|
|
1177
|
+
* Milliseconds to reuse a loaded tenant-membership policy. 帰属方針を再利用するミリ秒。
|
|
1178
|
+
*
|
|
1179
|
+
* 既定は 0 (毎回引き直す)。帰属証明は **権限を 1 件も読む前に毎リクエスト走る** ため、
|
|
1180
|
+
* 証明グループを 1 つも宣言していない配備でも 3 表の結合が 1 往復増える。
|
|
1181
|
+
*
|
|
1182
|
+
* ⚠️ 既定を非 0 にしない。認可の判断材料を、頼まれてもいないのに黙って古くするライブラリは
|
|
1183
|
+
* 信用できない。有効化は配備側が「どれだけ古くてよいか」を決めて明示する。
|
|
1184
|
+
* 本ストア自身の書き込み (証明グループの増減・連携の作成解除) は自動で破棄するため、
|
|
1185
|
+
* 遅れが出るのは **記憶域を直接編集した場合だけ** である。
|
|
1186
|
+
*/
|
|
1187
|
+
policyCacheTtlMs?: number;
|
|
1172
1188
|
};
|
|
1173
1189
|
/** One external link row as the admin surface sees it. 管理面が見る外部リンク行。 */
|
|
1174
1190
|
type DirectoryLinkRow = AuthGroupExternalLink & {
|
|
@@ -1437,6 +1453,16 @@ type PromotionRepositoryOptions = {
|
|
|
1437
1453
|
/** Injected clock — tests must not depend on wall time. 注入時計 (実時刻に依存させない)。 */
|
|
1438
1454
|
now?: () => Date;
|
|
1439
1455
|
};
|
|
1456
|
+
/**
|
|
1457
|
+
* Builds the promotion repository over the directory ledger and the authz membership table.
|
|
1458
|
+
* ディレクトリ台帳と認可の所属表に対して、昇格リポジトリを構築する処理。
|
|
1459
|
+
*
|
|
1460
|
+
* @param dbUnknown - Drizzle database instance. drizzle のデータベースインスタンス。
|
|
1461
|
+
* @param tables - Directory tables (owns the ledger). ディレクトリ表 (台帳の所有者)。
|
|
1462
|
+
* @param authzTables - Authorization tables (owns groups and membership). 認可表 (グループと所属の所有者)。
|
|
1463
|
+
* @param opts - Connection, actor and clock. 接続・実行者・時計。
|
|
1464
|
+
* @returns A repository consumable by `promoteLedgerForUser`. `promoteLedgerForUser` が使うリポジトリ。
|
|
1465
|
+
*/
|
|
1440
1466
|
declare function createPromotionRepository(dbUnknown: unknown, tables: AuthDirectoryTables, authzTables: AuthzTables, opts: PromotionRepositoryOptions): PromotionRepository;
|
|
1441
1467
|
|
|
1442
1468
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var O=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var de=Object.prototype.hasOwnProperty;var ue=(t,o)=>{for(var g in o)O(t,g,{get:o[g],enumerable:!0})},le=(t,o,g,I)=>{if(o&&typeof o=="object"||typeof o=="function")for(let i of ae(o))!de.call(t,i)&&i!==g&&O(t,i,{get:()=>o[i],enumerable:!(I=se(o,i))||I.enumerable});return t};var pe=t=>le(O({},"__esModule",{value:!0}),t);var Ge={};ue(Ge,{AUTH_DIRECTORY_PROVIDER_COLUMN:()=>ne,AUTH_DIRECTORY_TENANT_SCOPED_TABLES:()=>we,MAX_IN_LIST:()=>Ke,MAX_PARAMETERS:()=>te,MEMBERSHIP_MODES:()=>H,UNHEALTHY_SYNC_OUTCOMES:()=>W,assertGroupMayBeLinked:()=>ye,assertMembershipMode:()=>P,chunk:()=>M,chunkByParameters:()=>L,createDirectoryLinkStore:()=>ge,createDirectorySync:()=>Ae,createDirectorySyncRepository:()=>xe,createPromotionRepository:()=>fe,createSyncRequestQueue:()=>ve,defaultExternalGroupGuardMessage:()=>ce,defaultSyncMessages:()=>Y,defineAuthDirectorySchema:()=>Se,findLedgerRowsForIdentity:()=>N,promoteLedgerForUser:()=>he,withExternalGroupGuards:()=>me});module.exports=pe(Ge);var Z=require("@aiquants/authz-core"),ce=(t,o)=>`\u5916\u90E8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u9023\u643A\u30B0\u30EB\u30FC\u30D7 (${o}) \u306B\u306F\u7BA1\u7406\u30ED\u30FC\u30EB (${t}) \u3092\u6301\u305F\u305B\u3089\u308C\u307E\u305B\u3093\u3002\u4E0A\u6D41\u5074\u306E\u6240\u5C5E\u5909\u66F4\u304C\u305D\u306E\u307E\u307E\u7BA1\u7406\u8005\u306E\u5897\u6E1B\u306B\u306A\u308B\u305F\u3081\u3001\u7BA1\u7406\u8005\u7D4C\u8DEF\u306F\u30ED\u30FC\u30AB\u30EB\u7BA1\u7406\u306E\u30B0\u30EB\u30FC\u30D7\u306B\u9650\u5B9A\u3057\u3066\u3044\u307E\u3059\u3002`;function C(t,o,g,I){return new Set(t.filter(i=>i.roleId===o&&i.appKey===g&&i.resourceKey===I).map(i=>i.action))}var j=t=>Z.AUTHZ_ACTIONS.every(o=>t.has(o)),F=(t,o)=>t.find(g=>g.roleId===o)?.roleKey??`#${o}`;function me(t,o){let g=t;async function I(i,a,n){if(a.size===0)return;let c=await g.listGroupRoles(i),p=new Set;for(let u of c){if(!a.has(u.roleId)||p.has(u.groupId))continue;p.add(u.groupId);let f=await o.linkLookup.externalGroupKey(i,u.groupId);if(f!==null)throw new Error(o.message(u.roleKey||F(n,u.roleId),f))}}return{...t,async assignGroupRole(i,a,n,c){let p=await g.listGrants(i);if(j(C(p,n,o.adminAppKey,o.adminResourceKey))){let u=await o.linkLookup.externalGroupKey(i,a);if(u!==null)throw new Error(o.message(F(p,n),u))}return t.assignGroupRole(i,a,n,c)},async createGrant(i,a,n){let p=(await g.listResources(i)).find(u=>u.id===a.resourceId);if(p?.appKey===o.adminAppKey&&p?.resourceKey===o.adminResourceKey){let u=await g.listGrants(i),f=C(u,a.roleId,o.adminAppKey,o.adminResourceKey);f.add(a.action),j(f)&&await I(i,new Set([a.roleId]),u)}return t.createGrant(i,a,n)}}}async function ye(t,o,g,I){let i=(await t.listGroupRoles(o)).filter(n=>n.groupId===g);if(i.length===0)return;let a=await t.listGrants(o);for(let n of i)if(j(C(a,n.roleId,I.adminAppKey,I.adminResourceKey)))throw new Error(I.message(n.roleKey||F(a,n.roleId),n.groupKey))}var _=require("drizzle-orm");async function N(t,o,g){let{ledger:I,group:i}=o,{tenantId:a,externalUserId:n,email:c}=g;if(n===null&&c==="")return[];let p={ledgerId:I.id,groupId:I.groupId,tenantId:i.tenantId,externalUserId:I.externalUserId},u=async b=>(await t.select(p).from(I).innerJoin(i,(0,_.and)((0,_.eq)(i.id,I.groupId),(0,_.eq)(i.tenantId,a),(0,_.eq)(i.isActive,!0))).where(b)).map(S=>({ledgerId:Number(S.ledgerId),groupId:Number(S.groupId),tenantId:String(S.tenantId),externalUserId:S.externalUserId===null?null:String(S.externalUserId)})),f=b=>{let D=new Map;for(let S of b)D.set(S.ledgerId,{ledgerId:S.ledgerId,groupId:S.groupId,tenantId:S.tenantId});return[...D.values()].sort((S,r)=>S.ledgerId-r.ledgerId)},e=n===null?[]:await u((0,_.eq)(I.externalUserId,n));if(c==="")return f(e);let h=await u((0,_.eq)(I.email,c)),v=b=>n!==null&&b.externalUserId!==null&&b.externalUserId!==n;return f([...e,...h.filter(b=>!v(b))])}var q=require("@aiquants/auth-core"),ee=require("@aiquants/auth-directory-core"),x=require("@aiquants/authz-core"),d=require("drizzle-orm");var H=["direct","transitive"];function P(t){if(!H.includes(t))throw new TypeError(`[@aiquants/auth-directory-drizzle] membershipMode must be one of ${H.join(" | ")}, received ${JSON.stringify(t)}`);return t}function ge(t,o,g,I){let i=t,a=I.ensureConnection??(async()=>{}),{TDGroupExternalLink:n,TDGroupMemberEmail:c,TDTenantMembershipGroup:p,TDAllowlistGroup:u,TDDirectorySyncRequest:f}=o,{TMGroup:e,TDGroupMember:h}=g;async function v(r,s,y){if((await r.select({groupId:p.groupId}).from(p).where((0,d.and)((0,d.eq)(p.tenantId,s),(0,d.eq)(p.groupId,y),(0,d.eq)(p.isBreakGlass,!0)))).length>0)throw new Error(`Group ${y} is a break-glass proof group; a break-glass proof path must be one the synchronization can never touch.`)}async function b(r,s,y){let[m]=await r.select({id:e.id}).from(e).where((0,d.and)((0,d.eq)(e.id,y),(0,d.eq)(e.tenantId,s)));if(!m)throw new Error(`Group not found in tenant: ${y}`)}function D(r,s){return{linkId:Number(r.linkId),groupId:Number(r.groupId),tenantId:String(r.tenantId),provider:String(r.provider),externalId:String(r.externalId),externalKey:String(r.externalKey),membershipMode:P(String(r.membershipMode)),isSyncEnabled:!!r.isSyncEnabled,...r.syncedAt?{syncedAt:new Date(r.syncedAt).toISOString()}:{},...r.syncError?{syncError:String(r.syncError)}:{},unresolvedCount:s}}async function S(r,s){let y=await r.select({groupId:c.groupId,n:(0,d.count)()}).from(c).innerJoin(e,(0,d.and)((0,d.eq)(e.id,c.groupId),(0,d.eq)(e.tenantId,s))).where((0,d.isNull)(c.resolvedUserId)).groupBy(c.groupId);return new Map(y.map(m=>[Number(m.groupId),Number(m.n)]))}return{async listLinks(r){(0,x.assertTenantId)(r,"listLinks(tenantId)"),await a();let s=await i.select({linkId:n.id,groupId:n.groupId,tenantId:n.tenantId,provider:n.provider,externalId:n.externalId,externalKey:n.externalKey,membershipMode:n.membershipMode,isSyncEnabled:n.isSyncEnabled,syncedAt:n.syncedAt,syncError:n.syncError}).from(n).where((0,d.eq)(n.tenantId,r)).orderBy((0,d.asc)(n.groupId)),y=await S(i,r);return s.map(m=>((0,x.assertTenantMatch)(r,String(m.tenantId),"listLinks(row.tenantId)"),D(m,y.get(Number(m.groupId))??0)))},async externalGroupKey(r,s){(0,x.assertTenantId)(r,"externalGroupKey(tenantId)"),await a();let[y]=await i.select({externalKey:n.externalKey}).from(n).where((0,d.and)((0,d.eq)(n.groupId,s),(0,d.eq)(n.tenantId,r)));return y?String(y.externalKey):null},async linkGroup(r,s,y,m){(0,x.assertTenantId)(r,"linkGroup(tenantId)");let w=P(y.membershipMode),T=y.externalId.trim(),R=(0,q.normalizeAuthEmail)(y.externalKey);if(T===""||R==="")throw new TypeError("[@aiquants/auth-directory-drizzle] externalId and externalKey must be non-empty");await a(),await I.linkable.assertLinkable(r,s),await i.transaction(async K=>{await b(K,r,s),await v(K,r,s),await K.insert(n).output().values({groupId:s,tenantId:r,provider:y.provider,externalId:T,externalKey:R,membershipMode:w,isSyncEnabled:!0,vanishedObservations:0,createdAt:new Date,createdBy:m})})},async unlinkGroup(r,s){(0,x.assertTenantId)(r,"unlinkGroup(tenantId)"),await a(),await i.transaction(async y=>{await b(y,r,s),await y.delete(c).where((0,d.eq)(c.groupId,s)),await y.delete(u).where((0,d.and)((0,d.eq)(u.groupId,s),(0,d.eq)(u.tenantId,r))),await y.delete(n).where((0,d.and)((0,d.eq)(n.groupId,s),(0,d.eq)(n.tenantId,r)))})},async setSyncEnabled(r,s,y,m){(0,x.assertTenantId)(r,"setSyncEnabled(tenantId)"),await a(),await i.update(n).set({isSyncEnabled:y,updatedAt:new Date,updatedBy:m}).output().where((0,d.and)((0,d.eq)(n.groupId,s),(0,d.eq)(n.tenantId,r)))},async requestSync(r,s,y){(0,x.assertTenantId)(r,"requestSync(tenantId)"),await a(),await i.transaction(async m=>{s!==null&&await b(m,r,s),await m.insert(f).output().values({tenantId:r,groupId:s,requestedBy:y,requestedAt:new Date,createdAt:new Date,createdBy:y})})},async getStatus(r){(0,x.assertTenantId)(r,"getStatus(tenantId)"),await a();let s=await i.select({groupId:n.groupId,isSyncEnabled:n.isSyncEnabled,syncedAt:n.syncedAt,syncError:n.syncError}).from(n).where((0,d.eq)(n.tenantId,r)),[y]=await i.select({n:(0,d.count)()}).from(f).where((0,d.and)((0,d.eq)(f.tenantId,r),(0,d.isNull)(f.finishedAt))),m=s.filter(k=>!!k.isSyncEnabled),w=m.map(k=>k.syncedAt?new Date(k.syncedAt).getTime():null),T=w.length>0&&w.every(k=>k!==null)?Math.min(...w):null,K=s.length>0&&m.length===0||m.length>0&&(T===null||Date.now()-T>I.stalenessThresholdSec*1e3);return{isEnabled:I.isEnabled,linkedGroupCount:s.length,...T!==null?{oldestSyncedAt:new Date(T).toISOString()}:{},isStale:K,pausedGroupCount:s.length-m.length,stalenessThresholdSec:I.stalenessThresholdSec,erroredGroupIds:s.filter(k=>!!k.syncError).map(k=>Number(k.groupId)).sort((k,ie)=>k-ie),pendingRequestCount:Number(y?.n??0)}},async loadTenantMembershipPolicy(r){(0,x.assertTenantId)(r,"loadTenantMembershipPolicy(tenantId)"),await a();let s=await i.select({groupId:p.groupId,isBreakGlass:p.isBreakGlass,externalLinkId:n.id}).from(p).innerJoin(e,(0,d.and)((0,d.eq)(e.id,p.groupId),(0,d.eq)(e.tenantId,r))).leftJoin(n,(0,d.eq)(n.groupId,p.groupId)).where((0,d.eq)(p.tenantId,r));if(s.length===0)return{kind:"no-proof-required"};let y=s.map(T=>Number(T.groupId)),m=s.filter(T=>!!T.isBreakGlass);for(let T of m)if(T.externalLinkId!==null)throw new Error(`Break-glass group ${Number(T.groupId)} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`);let w={kind:"require-proof",proofGroupIds:y,breakGlassGroupIds:m.map(T=>Number(T.groupId))};return(0,ee.assertTenantMembershipPolicy)(w,`tenant ${r}`),w},async setTenantMembershipGroup(r,s,y,m){(0,x.assertTenantId)(r,"setTenantMembershipGroup(tenantId)"),await a(),await i.transaction(async w=>{if(await b(w,r,s),y){let[R]=await w.select({id:n.id}).from(n).where((0,d.and)((0,d.eq)(n.tenantId,r),(0,d.eq)(n.groupId,s)));if(R)throw new Error(`Group ${s} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`)}if((await w.select({groupId:p.groupId}).from(p).where((0,d.and)((0,d.eq)(p.tenantId,r),(0,d.eq)(p.groupId,s)))).length>0){await w.update(p).set({isBreakGlass:y,updatedAt:new Date,updatedBy:m}).output().where((0,d.and)((0,d.eq)(p.tenantId,r),(0,d.eq)(p.groupId,s)));return}await w.insert(p).output().values({tenantId:r,groupId:s,isBreakGlass:y,createdAt:new Date,createdBy:m})})},async removeTenantMembershipGroup(r,s){(0,x.assertTenantId)(r,"removeTenantMembershipGroup(tenantId)"),await a(),await i.transaction(async y=>{let w=(await y.select({groupId:p.groupId,isBreakGlass:p.isBreakGlass}).from(p).where((0,d.eq)(p.tenantId,r))).filter(T=>Number(T.groupId)!==s);if(w.length>0&&!w.some(T=>!!T.isBreakGlass))throw new Error(`Removing group ${s} would leave tenant ${r} with a membership proof but no break-glass path.`);await y.delete(p).where((0,d.and)((0,d.eq)(p.tenantId,r),(0,d.eq)(p.groupId,s)))})},async setGroupActive(r,s,y,m){(0,x.assertTenantId)(r,"setGroupActive(tenantId)"),await a(),await i.update(e).set({isActive:y,updatedAt:new Date,updatedBy:m}).output().where((0,d.and)((0,d.eq)(e.id,s),(0,d.eq)(e.tenantId,r)))},async listLedgerGroupIds(r,s){if((0,x.assertTenantId)(r,"listLedgerGroupIds(tenantId)"),!I.isEnabled)return[];await a();let y=await N(i,{ledger:c,group:e},{tenantId:r,externalUserId:s.externalUserId?.trim()||null,email:(0,q.normalizeAuthEmail)(s.email)});return[...new Set(y.map(m=>m.groupId))].sort((m,w)=>m-w)},async isEmailAllowedByGroup(r){if(!I.isEnabled)return!1;let s=(0,q.normalizeAuthEmail)(r);if(s==="")return!1;await a();let[y]=await i.select({id:c.id}).from(c).innerJoin(u,(0,d.eq)(u.groupId,c.groupId)).innerJoin(e,(0,d.and)((0,d.eq)(e.id,c.groupId),(0,d.eq)(e.isActive,!0))).where((0,d.eq)(c.email,s));return!!y},async listAllowlistGroups(r){return(0,x.assertTenantId)(r,"listAllowlistGroups(tenantId)"),await a(),(await i.select({id:u.id,groupId:u.groupId,groupKey:e.groupKey,groupName:e.name,description:u.description}).from(u).innerJoin(e,(0,d.and)((0,d.eq)(e.id,u.groupId),(0,d.eq)(e.tenantId,r))).where((0,d.eq)(u.tenantId,r)).orderBy((0,d.asc)(e.name))).map(y=>({id:Number(y.id),type:"group",groupId:Number(y.groupId),groupKey:String(y.groupKey),groupName:String(y.groupName),...y.description?{description:String(y.description)}:{},owner:{kind:"tenant",tenantId:r},readOnly:!1}))},async addAllowlistGroup(r,s,y,m){(0,x.assertTenantId)(r,"addAllowlistGroup(tenantId)"),await a(),await i.transaction(async w=>{await b(w,r,s);let[T]=await w.select({id:n.id}).from(n).where((0,d.and)((0,d.eq)(n.groupId,s),(0,d.eq)(n.tenantId,r)));if(!T)throw new Error(`Group ${s} is locally managed; only externally-sourced groups can gate sign-in, because the decision reads the upstream member ledger.`);await w.insert(u).output().values({tenantId:r,groupId:s,description:y??null,createdAt:new Date,createdBy:m})})},async removeAllowlistGroup(r,s){(0,x.assertTenantId)(r,"removeAllowlistGroup(tenantId)"),await a(),await i.delete(u).where((0,d.and)((0,d.eq)(u.id,s),(0,d.eq)(u.tenantId,r)))},async countProjectedMembers(r,s){(0,x.assertTenantId)(r,"countProjectedMembers(tenantId)"),await a();let[y]=await i.select({n:(0,d.count)()}).from(h).innerJoin(e,(0,d.and)((0,d.eq)(e.id,h.groupId),(0,d.eq)(e.tenantId,r))).where((0,d.eq)(h.groupId,s));return Number(y?.n??0)}}}var re=require("@aiquants/auth-core"),z=require("@aiquants/authz-core");async function he(t,o){let g=(0,z.assertTenantId)(o.tenantId,"promoteLedgerForUser(tenantId)");if(!Number.isInteger(o.userId)||o.userId<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] userId must be a positive integer, received ${String(o.userId)}`);let I=(0,re.normalizeAuthEmail)(o.email),i=o.externalUserId?.trim()||null;if(i===null&&I==="")return{addedGroupIds:[],matchedLedgerIds:[]};let a=await t.findLedgerMatches({tenantId:g,externalUserId:i,email:I});if(a.length===0)return{addedGroupIds:[],matchedLedgerIds:[]};for(let u of a)(0,z.assertTenantMatch)(g,u.tenantId,"promoteLedgerForUser(findLedgerMatches row)");let n=[...new Set(a.map(u=>u.ledgerId))].sort((u,f)=>u-f),c=[...new Set(a.map(u=>u.groupId))].sort((u,f)=>u-f);return{addedGroupIds:[...await t.attachUserToGroups({tenantId:g,userId:o.userId,ledgerIds:n,groupIds:c})].sort((u,f)=>u-f),matchedLedgerIds:n}}var J=require("@aiquants/authz-core"),G=require("drizzle-orm");var te=2100;var Ke=500;function M(t,o=500){if(!Number.isInteger(o)||o<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] chunk size must be a positive integer, received ${String(o)}`);let g=[];for(let I=0;I<t.length;I+=o)g.push(t.slice(I,I+o));return g}function L(t,o,g=100){if(!Number.isInteger(o)||o<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] parametersPerItem must be a positive integer, received ${String(o)}`);if(!Number.isInteger(g)||g<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] reservedParameters must be a non-negative integer, received ${String(g)}`);let I=2100-g,i=Math.floor(I/o);if(i<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] a single item binds ${o} parameters, which exceeds the ${I} available in one statement`);return M(t,i)}var be=4,Ie=100;function fe(t,o,g,I){let i=t,a=I.ensureConnection??(async()=>{}),n=I.now??(()=>new Date),c=o.TDGroupMemberEmail,{TMGroup:p,TDGroupMember:u}=g;return{async findLedgerMatches(f){return(0,J.assertTenantId)(f.tenantId,"findLedgerMatches(tenantId)"),await a(),N(i,{ledger:c,group:p},f)},async attachUserToGroups({tenantId:f,userId:e,ledgerIds:h,groupIds:v}){return(0,J.assertTenantId)(f,"attachUserToGroups(tenantId)"),await a(),h.length===0?[]:i.transaction(async b=>{let D=new Set;for(let m of M(v)){let w=await b.select({id:p.id}).from(p).where((0,G.and)((0,G.inArray)(p.id,m),(0,G.eq)(p.tenantId,f),(0,G.eq)(p.isActive,!0)));for(let T of w)D.add(Number(T.id))}let S=v.filter(m=>D.has(m));if(S.length===0)return[];let r=new Set;for(let m of M(S)){let w=await b.select({groupId:u.groupId}).from(u).where((0,G.and)((0,G.eq)(u.userId,e),(0,G.inArray)(u.groupId,m)));for(let T of w)r.add(Number(T.groupId))}let s=S.filter(m=>!r.has(m)),y=Math.max(1,2100-Ie-S.length);for(let m of M(h,y))await b.update(c).set({resolvedUserId:e}).output().where((0,G.and)((0,G.inArray)(c.id,m),(0,G.inArray)(c.groupId,S)));if(s.length>0){let m=n();for(let w of L(s,be))await b.insert(u).output().values(w.map(T=>({groupId:T,userId:e,createdAt:m,createdBy:I.actor})))}return s})}}}var $=require("@aiquants/authz-drizzle"),l=require("drizzle-orm/mssql-core"),ne="provider",we=["TDGroupExternalLink","TDTenantMembershipGroup","TDAllowlistGroup","TDDirectorySyncRequest","TMAllowlist"];function Se(t,o){let g=(0,l.mssqlSchema)(t),I=()=>({createdAt:(0,l.datetime2)("created_at"),createdBy:(0,l.nvarchar)("created_by",{length:50}),updatedAt:(0,l.datetime2)("updated_at"),updatedBy:(0,l.nvarchar)("updated_by",{length:50})}),i=()=>({createdAt:(0,l.datetime2)("created_at"),createdBy:(0,l.nvarchar)("created_by",{length:50})}),a=g.table("TDGroupExternalLink",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,l.bigint)("group_id",{mode:"number"}).notNull(),tenantId:(0,l.nvarchar)($.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),provider:(0,l.nvarchar)(ne,{length:32}).notNull(),externalId:(0,l.nvarchar)("external_id",{length:256}).notNull(),externalKey:(0,l.nvarchar)("external_key",{length:320}).notNull(),membershipMode:(0,l.nvarchar)("membership_mode",{length:16}).notNull(),isSyncEnabled:(0,l.bit)("is_sync_enabled").notNull(),syncedAt:(0,l.datetime2)("synced_at"),syncError:(0,l.nvarchar)("sync_error",{length:1e3}),vanishedObservations:(0,l.int)("vanished_observations").notNull(),...I()},e=>[(0,l.primaryKey)({name:`${t}_TDGroupExternalLink_pk`,columns:[e.id]}),(0,l.uniqueIndex)(`${t}_TDGroupExternalLink_group_uq`).on(e.groupId),(0,l.uniqueIndex)(`${t}_TDGroupExternalLink_external_uq`).on(e.tenantId,e.provider,e.externalId),(0,l.foreignKey)({name:`${t}_TDGroupExternalLink_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),n=g.table("TDGroupMemberEmail",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,l.bigint)("group_id",{mode:"number"}).notNull(),email:(0,l.nvarchar)("email",{length:320}).notNull(),externalUserId:(0,l.nvarchar)("external_user_id",{length:128}),resolvedUserId:(0,l.bigint)("resolved_user_id",{mode:"number"}),observedAt:(0,l.datetime2)("observed_at").notNull(),...I()},e=>[(0,l.primaryKey)({name:`${t}_TDGroupMemberEmail_pk`,columns:[e.id]}),(0,l.uniqueIndex)(`${t}_TDGroupMemberEmail_group_email_uq`).on(e.groupId,e.email),(0,l.foreignKey)({name:`${t}_TDGroupMemberEmail_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),c=g.table("TDTenantMembershipGroup",{tenantId:(0,l.nvarchar)($.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,l.bigint)("group_id",{mode:"number"}).notNull(),isBreakGlass:(0,l.bit)("is_break_glass").notNull(),...i()},e=>[(0,l.primaryKey)({name:`${t}_TDTenantMembershipGroup_pk`,columns:[e.tenantId,e.groupId]}),(0,l.foreignKey)({name:`${t}_TDTenantMembershipGroup_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),p=g.table("TDAllowlistGroup",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,l.nvarchar)($.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,l.bigint)("group_id",{mode:"number"}).notNull(),description:(0,l.nvarchar)("description",{length:512}),...i()},e=>[(0,l.primaryKey)({name:`${t}_TDAllowlistGroup_pk`,columns:[e.id]}),(0,l.uniqueIndex)(`${t}_TDAllowlistGroup_tenant_group_uq`).on(e.tenantId,e.groupId),(0,l.foreignKey)({name:`${t}_TDAllowlistGroup_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),u=g.table("TDDirectorySyncRequest",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,l.nvarchar)($.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,l.bigint)("group_id",{mode:"number"}),requestedBy:(0,l.nvarchar)("requested_by",{length:320}).notNull(),requestedAt:(0,l.datetime2)("requested_at").notNull(),pickedAt:(0,l.datetime2)("picked_at"),finishedAt:(0,l.datetime2)("finished_at"),result:(0,l.nvarchar)("result",{length:32}),error:(0,l.nvarchar)("error",{length:2e3}),...i()},e=>[(0,l.primaryKey)({name:`${t}_TDDirectorySyncRequest_pk`,columns:[e.id]})]),f=g.table("TMAllowlist",{id:(0,l.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,l.nvarchar)($.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),pattern:(0,l.nvarchar)("pattern",{length:256}).notNull(),type:(0,l.nvarchar)("type",{length:32}).notNull(),description:(0,l.nvarchar)("description",{length:512}),...i()},e=>[(0,l.primaryKey)({name:`${t}_TMAllowlist_pk`,columns:[e.id]}),(0,l.uniqueIndex)(`${t}_TMAllowlist_pattern_uq`).on(e.tenantId,e.pattern)]);return{TDGroupExternalLink:a,TDGroupMemberEmail:n,TDTenantMembershipGroup:c,TDAllowlistGroup:p,TDDirectorySyncRequest:u,TMAllowlist:f}}var B=require("@aiquants/auth-directory-core");var V=(t,o=20)=>t.length<=o?t.join(", "):`${t.slice(0,o).join(", ")} \u307B\u304B ${t.length-o} \u4EF6`,Y={upstreamUnreadable:t=>`\u4E0A\u6D41\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8AAD\u307F\u53D6\u308A\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${t}`,localWriteFailed:t=>`\u30ED\u30FC\u30AB\u30EB\u3078\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${t}`,resolverIncomplete:(t,o)=>`\u4E0A\u6D41\u304C ${t} \u4EF6\u306E\u30E1\u30F3\u30D0\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F\u304C\u3001\u7A81\u5408\u7D50\u679C\u306F ${o} \u4EF6\u3067\u3057\u305F\u3002\u4EF6\u6570\u304C\u6E1B\u308B\u7A81\u5408\u306F\u3001\u89E3\u6C7A\u3067\u304D\u306A\u304B\u3063\u305F\u4EBA\u7269\u3092\u300C\u4E0A\u6D41\u304B\u3089\u6D88\u3048\u305F\u300D\u3068\u3057\u3066\u524A\u9664\u3057\u3066\u3057\u307E\u3046\u305F\u3081\u4E2D\u65AD\u3057\u307E\u3057\u305F\u3002\u89E3\u6C7A\u3067\u304D\u306A\u3044\u30E1\u30F3\u30D0\u30FC\u306F\u7701\u7565\u305B\u305A resolvedUserId: null \u3067\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002`,groupMissing:(t,o,g)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${t})\u3002\u9023\u7D9A ${o} \u56DE\u76EE\u3067\u3059\u3002${g} \u56DE\u306B\u9054\u3057\u305F\u6642\u70B9\u3067\u30B0\u30EB\u30FC\u30D7\u3092\u7121\u52B9\u5316\u3057\u307E\u3059\u3002`,groupVanished:(t,o)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C ${o} \u56DE\u9023\u7D9A\u3067\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F (${t})\u3002\u30B0\u30EB\u30FC\u30D7\u3092\u7121\u52B9\u5316\u3057\u307E\u3057\u305F\u3002\u4E0A\u6D41\u304C\u5FA9\u65E7\u3059\u308C\u3070\u6B21\u56DE\u306E\u540C\u671F\u3067\u81EA\u52D5\u7684\u306B\u518D\u6709\u52B9\u5316\u3055\u308C\u307E\u3059\u3002`,planRefused:t=>{if(t.reason==="invalid-upstream-data")return`\u540C\u671F\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F: \u4E0A\u6D41\u306E\u30E1\u30F3\u30D0\u30FC\u4E00\u89A7\u306B\u6271\u3048\u306A\u3044\u30A2\u30C9\u30EC\u30B9\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 (${V(t.offendingEmails)})\u3002`;let o=t.axis==="membership"?"\u6A29\u9650\u3092\u5931\u3046\u4EBA\u6570":"\u30B5\u30A4\u30F3\u30A4\u30F3\u3067\u304D\u306A\u304F\u306A\u308B\u4EBA\u6570",g=t.axis==="membership"?t.withheldProjectionRemoves.map(String):t.withheldLedgerDeletes;return[`\u540C\u671F\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F: ${o}\u304C ${t.population} \u4EBA\u4E2D ${t.removalCount} \u4EBA\u306B\u306A\u308A\u307E\u3059`,`(\u4E0A\u9650: ${t.limits.maxRemovalCount} \u4EF6 / \u6BD4\u7387 ${t.limits.maxRemovalRatio})\u3002`,`\u5DEE\u3057\u6B62\u3081\u305F\u5BFE\u8C61: ${V(g)}\u3002`,"\u4E0A\u6D41\u5074\u306E\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u610F\u56F3\u3057\u305F\u5909\u66F4\u3067\u3042\u308C\u3070\u3001\u3053\u306E\u8EF8\u306E\u4E0A\u9650\u3060\u3051\u3092\u4E00\u6642\u7684\u306B\u5F15\u304D\u4E0A\u3052\u3066\u518D\u5B9F\u884C\u3057\u307E\u3059\u3002"].join(" ")},removalsRefused:t=>`${t.length} \u4EF6\u306E\u6240\u5C5E\u89E3\u9664\u304C\u6700\u5F8C\u306E\u7BA1\u7406\u8005\u30AC\u30FC\u30C9\u306B\u3088\u308A\u62D2\u5426\u3055\u308C\u307E\u3057\u305F (\u30E6\u30FC\u30B6\u30FC ${V(t.map(o=>String(o.userId)))})\u3002\u6B8B\u308A\u306E\u5909\u66F4\u306F\u9069\u7528\u6E08\u307F\u3067\u3059\u3002`,foreignProvider:(t,o)=>`\u3053\u306E\u30EA\u30F3\u30AF\u306E\u4F9B\u7D66\u5143\u306F ${t} \u3067\u3059\u304C\u3001\u5B9F\u884C\u4E2D\u306E\u540C\u671F\u306F ${o} \u7528\u3067\u3059\u3002\u5BFE\u5FDC\u3059\u308B\u540C\u671F\u30B8\u30E7\u30D6\u304B\u3089\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002`};var W=["aborted","missing","vanished","upstream-failed","local-failed","foreign-provider"];function Ae(t){let{directory:o,repository:g,policy:I,now:i,logger:a}=t,n=t.messages??Y;if((0,B.assertBlastRadiusPolicy)(I),!Number.isInteger(t.vanishedThreshold)||t.vanishedThreshold<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] vanishedThreshold must be a positive integer, received ${String(t.vanishedThreshold)}`);if(typeof t.provider!="string"||t.provider.trim()==="")throw new TypeError("[@aiquants/auth-directory-drizzle] provider must be a non-empty string so links of other providers can be told apart");async function c(e,h){try{await g.recordFailure(e,h)}catch(v){a.error(`[auth-directory] could not record the failure for ${e.externalKey}:`,v)}}async function p(e){try{let h=await o.getGroup(e.externalId);return h===null?{kind:"missing"}:{kind:"ok",group:h,members:await o.listGroupMembers(h,e.membershipMode)}}catch(h){return{kind:"failed",error:h instanceof Error?h:new Error(String(h))}}}async function u(e){let h=await g.recordVanishedObservation(e,n.groupMissing(e.externalKey,e.vanishedObservations+1,t.vanishedThreshold));return h<t.vanishedThreshold?(a.warn(`[auth-directory] ${e.externalKey} missing upstream (${h}/${t.vanishedThreshold})`),{kind:"missing",link:e,observations:h}):(await g.markGroupInactive(e),await c(e,n.groupVanished(e.externalKey,h)),a.warn(`[auth-directory] ${e.externalKey} deactivated after ${h} consecutive absences`),{kind:"vanished",link:e})}async function f(e){if(e.provider!==t.provider)return await c(e,n.foreignProvider(e.provider,t.provider)),a.warn(`[auth-directory] skipping ${e.externalKey}: belongs to provider ${e.provider}`),{kind:"foreign-provider",link:e};let h=await p(e);if(h.kind==="missing")return u(e);if(h.kind==="failed")return await c(e,n.upstreamUnreadable(h.error.message)),a.error(`[auth-directory] upstream read failed for ${e.externalKey}:`,h.error),{kind:"upstream-failed",link:e,error:h.error};try{let[v,b]=await Promise.all([g.loadGroupSnapshot(e),g.resolveMembers(h.members)]);if(b.length!==h.members.length){let y=n.resolverIncomplete(h.members.length,b.length);return await c(e,y),a.error(`[auth-directory] ${y}`),{kind:"local-failed",link:e,error:new Error(y)}}let D=(0,B.reconcile)(v,b,I);if(D.aborted)return await c(e,n.planRefused(D.aborted)),a.warn(`[auth-directory] plan refused for ${e.externalKey}: ${D.aborted.reason}`),{kind:"aborted",link:e,plan:D};let S=D.ledgerUpserts.length>0||D.ledgerDeletes.length>0||D.projectionAdds.length>0||D.projectionRemoves.length>0,r=i(),s={refusals:[]};return S&&(s=await g.applyPlan(e,D,r)),await g.recordSuccess(e,h.group,r),s.refusals.length>0&&(await c(e,n.removalsRefused(s.refusals)),a.warn(`[auth-directory] ${s.refusals.length} removal(s) refused for ${e.externalKey}`)),D.unresolvedEmails.length>0&&a.info(`[auth-directory] ${e.externalKey}: ${D.unresolvedEmails.length} upstream member(s) have no local user yet`),S?{kind:"applied",link:e,plan:D}:{kind:"unchanged",link:e}}catch(v){let b=v instanceof Error?v:new Error(String(v));return await c(e,n.localWriteFailed(b.message)),a.error(`[auth-directory] local write failed for ${e.externalKey}:`,b),{kind:"local-failed",link:e,error:b}}}return{syncOne:f,async run(e={}){let h=await g.listSyncableLinks(e),v=[];for(let D of h)try{v.push(await f(D))}catch(S){let r=S instanceof Error?S:new Error(String(S));a.error(`[auth-directory] ${D.externalKey} ended abnormally:`,r),v.push({kind:"local-failed",link:D,error:r})}let b=v.filter(D=>W.includes(D.kind)).length;return a.info(`[auth-directory] run finished: ${v.length} link(s), ${b} unhealthy`),{outcomes:v,unhealthyCount:b}}}}var oe=require("@aiquants/authz-core"),E=require("drizzle-orm"),X=2e3;function ve(t,o,g){let I=t,i=g.ensureConnection??(async()=>{}),a=o.TDDirectorySyncRequest,n=g.maxErrorLength??X;if(!Number.isInteger(n)||n<1||n>X)throw new TypeError(`[@aiquants/auth-directory-drizzle] maxErrorLength must be an integer within 1..${X}, received ${String(g.maxErrorLength)}`);return{async claim(){await i();let c=await I.select({id:a.id}).from(a).where((0,E.isNull)(a.pickedAt)).orderBy((0,E.asc)(a.id));for(let p of c){let f=(await I.update(a).set({pickedAt:g.now()}).output().where((0,E.and)((0,E.eq)(a.id,Number(p.id)),(0,E.isNull)(a.pickedAt))))?.[0];if(!f)continue;let e=String(f.tenant_id??f.tenantId??""),h=f.group_id??f.groupId??null;return{id:Number(f.id),tenantId:(0,oe.assertTenantId)(e,"claim(row.tenantId)"),groupId:h===null?null:Number(h),requestedBy:String(f.requested_by??f.requestedBy??"")}}return null},async finish(c,p){await i();let u=p.error?p.error.slice(0,n):null;await I.update(a).set({finishedAt:g.now(),result:p.result,error:u}).output().where((0,E.eq)(a.id,c))},async listStranded(c){return await i(),(await I.select({id:a.id,pickedAt:a.pickedAt}).from(a).where((0,E.isNull)(a.finishedAt)).orderBy((0,E.asc)(a.id))).filter(u=>u.pickedAt!==null&&new Date(u.pickedAt)<c).map(u=>Number(u.id))}}}var Q=require("@aiquants/auth-core"),U=require("@aiquants/authz-core"),A=require("drizzle-orm");var Te=7,De=4;function xe(t,o,g,I){let i=t,a=I.ensureConnection??(async()=>{}),{TDGroupExternalLink:n,TDGroupMemberEmail:c}=o,{TMGroup:p,TDGroupMember:u}=g,f=I.actor;return{async listSyncableLinks(e){await a();let h=[(0,A.eq)(n.isSyncEnabled,!0)];return e.tenantId!==void 0&&h.push((0,A.eq)(n.tenantId,(0,U.assertTenantId)(e.tenantId,"listSyncableLinks(tenantId)"))),e.groupId!==void 0&&h.push((0,A.eq)(n.groupId,e.groupId)),(await i.select({linkId:n.id,groupId:n.groupId,linkTenantId:n.tenantId,groupTenantId:p.tenantId,groupKey:p.groupKey,isGroupActive:p.isActive,provider:n.provider,externalId:n.externalId,externalKey:n.externalKey,membershipMode:n.membershipMode,vanishedObservations:n.vanishedObservations}).from(n).innerJoin(p,(0,A.eq)(p.id,n.groupId)).where((0,A.and)(...h))).map(b=>((0,U.assertTenantMatch)(String(b.groupTenantId),String(b.linkTenantId),"listSyncableLinks(link.tenantId vs TMGroup.tenant_id)"),{linkId:Number(b.linkId),groupId:Number(b.groupId),groupKey:String(b.groupKey),tenantId:String(b.groupTenantId),provider:String(b.provider),externalId:String(b.externalId),externalKey:String(b.externalKey),membershipMode:P(String(b.membershipMode)),isGroupActive:!!b.isGroupActive,vanishedObservations:Number(b.vanishedObservations??0)}))},async loadGroupSnapshot(e){await a();let[h,v]=await Promise.all([i.select({email:c.email,externalUserId:c.externalUserId,resolvedUserId:c.resolvedUserId}).from(c).where((0,A.eq)(c.groupId,e.groupId)),i.select({userId:u.userId}).from(u).where((0,A.eq)(u.groupId,e.groupId))]);return{ledger:h.map(b=>({email:String(b.email),...b.externalUserId?{externalUserId:String(b.externalUserId)}:{},resolvedUserId:b.resolvedUserId===null?null:Number(b.resolvedUserId)})),projectedUserIds:v.map(b=>Number(b.userId))}},resolveMembers(e){return I.memberResolver.resolve(e)},async applyPlan(e,h,v){(0,U.assertTenantId)(e.tenantId,"applyPlan(link.tenantId)"),await a(),(h.ledgerUpserts.length>0||h.projectionAdds.length>0)&&await i.transaction(async S=>{let r=h.ledgerUpserts.map(m=>({...m,email:(0,Q.normalizeAuthEmail)(m.email)})),s=new Map;for(let m of M(r.map(w=>w.email))){let w=await S.select({id:c.id,email:c.email}).from(c).where((0,A.and)((0,A.eq)(c.groupId,e.groupId),(0,A.inArray)(c.email,m)));for(let T of w)s.set(String(T.email),Number(T.id))}let y=r.filter(m=>!s.has(m.email));for(let m of L(y,Te))await S.insert(c).output().values(m.map(w=>({groupId:e.groupId,email:w.email,externalUserId:w.externalUserId??null,resolvedUserId:w.resolvedUserId,observedAt:v,createdAt:v,createdBy:f})));for(let m of r){let w=s.get(m.email);w!==void 0&&await S.update(c).set({externalUserId:m.externalUserId??null,resolvedUserId:m.resolvedUserId,observedAt:v,updatedAt:v,updatedBy:f}).output().where((0,A.eq)(c.id,w))}for(let m of L(h.projectionAdds,De)){let w=new Set((await S.select({userId:u.userId}).from(u).where((0,A.and)((0,A.eq)(u.groupId,e.groupId),(0,A.inArray)(u.userId,m)))).map(R=>Number(R.userId))),T=m.filter(R=>!w.has(R));T.length>0&&await S.insert(u).output().values(T.map(R=>({groupId:e.groupId,userId:R,createdAt:v,createdBy:f})))}});let b=[];for(let S of h.projectionRemoves)try{await I.lockoutGuard.guardedWrite(e.tenantId,{removeGroupMembership:{groupId:e.groupId,userId:S}},"remove-group-member",r=>r.delete(u).where((0,A.and)((0,A.eq)(u.groupId,e.groupId),(0,A.eq)(u.userId,S))))}catch(r){b.push({userId:S,applied:!1,refusal:r instanceof Error?r.message:String(r)})}let D=b.map(S=>S.userId);return h.ledgerDeletes.length>0&&await i.transaction(async S=>{for(let r of M(h.ledgerDeletes)){let s=D.length>0?(0,A.or)((0,A.isNull)(c.resolvedUserId),(0,A.notInArray)(c.resolvedUserId,D)):void 0;await S.delete(c).where((0,A.and)((0,A.eq)(c.groupId,e.groupId),(0,A.inArray)(c.email,r),...s?[s]:[]))}}),{refusals:b}},async recordSuccess(e,h,v){await a(),await i.transaction(async b=>{await b.update(n).set({syncedAt:v,syncError:null,vanishedObservations:0,externalId:h.externalId,externalKey:(0,Q.normalizeAuthEmail)(h.externalKey),updatedAt:v,updatedBy:f}).output().where((0,A.eq)(n.id,e.linkId)),e.isGroupActive||await b.update(p).set({isActive:!0,updatedAt:v,updatedBy:f}).output().where((0,A.and)((0,A.eq)(p.id,e.groupId),(0,A.eq)(p.tenantId,e.tenantId)))})},async recordFailure(e,h){await a(),await i.update(n).set({syncError:h.slice(0,1e3),updatedAt:new Date,updatedBy:f}).output().where((0,A.eq)(n.id,e.linkId))},async recordVanishedObservation(e,h){await a();let v=e.vanishedObservations+1;return await i.update(n).set({vanishedObservations:v,syncError:h.slice(0,1e3),updatedAt:new Date,updatedBy:f}).output().where((0,A.eq)(n.id,e.linkId)),v},async markGroupInactive(e){await a(),await i.update(p).set({isActive:!1,updatedAt:new Date,updatedBy:f}).output().where((0,A.and)((0,A.eq)(p.id,e.groupId),(0,A.eq)(p.tenantId,e.tenantId)))}}}0&&(module.exports={AUTH_DIRECTORY_PROVIDER_COLUMN,AUTH_DIRECTORY_TENANT_SCOPED_TABLES,MAX_IN_LIST,MAX_PARAMETERS,MEMBERSHIP_MODES,UNHEALTHY_SYNC_OUTCOMES,assertGroupMayBeLinked,assertMembershipMode,chunk,chunkByParameters,createDirectoryLinkStore,createDirectorySync,createDirectorySyncRepository,createPromotionRepository,createSyncRequestQueue,defaultExternalGroupGuardMessage,defaultSyncMessages,defineAuthDirectorySchema,findLedgerRowsForIdentity,promoteLedgerForUser,withExternalGroupGuards});
|
|
1
|
+
"use strict";var F=Object.defineProperty;var ue=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var pe=Object.prototype.hasOwnProperty;var ce=(t,o)=>{for(var y in o)F(t,y,{get:o[y],enumerable:!0})},me=(t,o,y,g)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of le(o))!pe.call(t,s)&&s!==y&&F(t,s,{get:()=>o[s],enumerable:!(g=ue(o,s))||g.enumerable});return t};var ye=t=>me(F({},"__esModule",{value:!0}),t);var Me={};ce(Me,{AUTH_DIRECTORY_PROVIDER_COLUMN:()=>se,AUTH_DIRECTORY_TENANT_SCOPED_TABLES:()=>ve,MAX_IN_LIST:()=>qe,MAX_PARAMETERS:()=>ie,MEMBERSHIP_MODES:()=>Y,UNHEALTHY_SYNC_OUTCOMES:()=>Z,assertGroupMayBeLinked:()=>be,assertMembershipMode:()=>K,chunk:()=>L,chunkByParameters:()=>N,createDirectoryLinkStore:()=>fe,createDirectorySync:()=>De,createDirectorySyncRepository:()=>Ee,createPromotionRepository:()=>Ae,createSyncRequestQueue:()=>xe,defaultExternalGroupGuardMessage:()=>ge,defaultSyncMessages:()=>Q,defineAuthDirectorySchema:()=>Te,findLedgerRowsForIdentity:()=>z,promoteLedgerForUser:()=>we,withExternalGroupGuards:()=>he});module.exports=ye(Me);var te=require("@aiquants/authz-core"),ge=(t,o)=>`\u5916\u90E8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u9023\u643A\u30B0\u30EB\u30FC\u30D7 (${o}) \u306B\u306F\u7BA1\u7406\u30ED\u30FC\u30EB (${t}) \u3092\u6301\u305F\u305B\u3089\u308C\u307E\u305B\u3093\u3002\u4E0A\u6D41\u5074\u306E\u6240\u5C5E\u5909\u66F4\u304C\u305D\u306E\u307E\u307E\u7BA1\u7406\u8005\u306E\u5897\u6E1B\u306B\u306A\u308B\u305F\u3081\u3001\u7BA1\u7406\u8005\u7D4C\u8DEF\u306F\u30ED\u30FC\u30AB\u30EB\u7BA1\u7406\u306E\u30B0\u30EB\u30FC\u30D7\u306B\u9650\u5B9A\u3057\u3066\u3044\u307E\u3059\u3002`;function H(t,o,y,g){return new Set(t.filter(s=>s.roleId===o&&s.appKey===y&&s.resourceKey===g).map(s=>s.action))}var J=t=>te.AUTHZ_ACTIONS.every(o=>t.has(o)),V=(t,o)=>t.find(y=>y.roleId===o)?.roleKey??`#${o}`;function he(t,o){let y=t;async function g(s,a,m){if(a.size===0)return;let b=await y.listGroupRoles(s),f=new Set;for(let n of b){if(!a.has(n.roleId)||f.has(n.groupId))continue;f.add(n.groupId);let h=await o.linkLookup.externalGroupKey(s,n.groupId);if(h!==null)throw new Error(o.message(n.roleKey||V(m,n.roleId),h))}}return{...t,async assignGroupRole(s,a,m,b){let f=await y.listGrants(s);if(J(H(f,m,o.adminAppKey,o.adminResourceKey))){let n=await o.linkLookup.externalGroupKey(s,a);if(n!==null)throw new Error(o.message(V(f,m),n))}return t.assignGroupRole(s,a,m,b)},async createGrant(s,a,m){let f=(await y.listResources(s)).find(n=>n.id===a.resourceId);if(f?.appKey===o.adminAppKey&&f?.resourceKey===o.adminResourceKey){let n=await y.listGrants(s),h=H(n,a.roleId,o.adminAppKey,o.adminResourceKey);h.add(a.action),J(h)&&await g(s,new Set([a.roleId]),n)}return t.createGrant(s,a,m)}}}async function be(t,o,y,g){let s=(await t.listGroupRoles(o)).filter(m=>m.groupId===y);if(s.length===0)return;let a=await t.listGrants(o);for(let m of s)if(J(H(a,m.roleId,g.adminAppKey,g.adminResourceKey)))throw new Error(g.message(m.roleKey||V(a,m.roleId),m.groupKey))}var $=require("drizzle-orm");async function z(t,o,y){let{ledger:g,group:s}=o,{tenantId:a,externalUserId:m,email:b}=y;if(m===null&&b==="")return[];let f={ledgerId:g.id,groupId:g.groupId,tenantId:s.tenantId,externalUserId:g.externalUserId},n=async d=>(await t.select(f).from(g).innerJoin(s,(0,$.and)((0,$.eq)(s.id,g.groupId),(0,$.eq)(s.tenantId,a),(0,$.eq)(s.isActive,!0))).where(d)).map(w=>({ledgerId:Number(w.ledgerId),groupId:Number(w.groupId),tenantId:String(w.tenantId),externalUserId:w.externalUserId===null?null:String(w.externalUserId)})),h=d=>{let v=new Map;for(let w of d)v.set(w.ledgerId,{ledgerId:w.ledgerId,groupId:w.groupId,tenantId:w.tenantId});return[...v.values()].sort((w,T)=>w.ledgerId-T.ledgerId)},e=m===null?[]:await n((0,$.eq)(g.externalUserId,m));if(b==="")return h(e);let l=await n((0,$.eq)(g.email,b)),S=d=>m!==null&&d.externalUserId!==null&&d.externalUserId!==m;return h([...e,...l.filter(d=>!S(d))])}var O=require("@aiquants/auth-core"),ne=require("@aiquants/auth-directory-core"),x=require("@aiquants/authz-core"),u=require("drizzle-orm");var Y=["direct","transitive"];function K(t){if(!Y.includes(t))throw new TypeError(`[@aiquants/auth-directory-drizzle] membershipMode must be one of ${Y.join(" | ")}, received ${JSON.stringify(t)}`);return t}function fe(t,o,y,g){let s=t,a=g.ensureConnection??(async()=>{}),m=g.policyCacheTtlMs??0;if(!Number.isFinite(m)||m<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] policyCacheTtlMs must be a non-negative number, received ${String(g.policyCacheTtlMs)}`);let b=new Map,f=r=>b.delete(r),{TDGroupExternalLink:n,TDGroupMemberEmail:h,TDTenantMembershipGroup:e,TDAllowlistGroup:l,TDDirectorySyncRequest:S}=o,{TMGroup:d,TDGroupMember:v}=y;async function w(r,i,p){if((await r.select({groupId:e.groupId}).from(e).where((0,u.and)((0,u.eq)(e.tenantId,i),(0,u.eq)(e.groupId,p),(0,u.eq)(e.isBreakGlass,!0)))).length>0)throw new Error(`Group ${p} is a break-glass proof group; a break-glass proof path must be one the synchronization can never touch.`)}async function T(r,i,p){let[I]=await r.select({id:d.id}).from(d).where((0,u.and)((0,u.eq)(d.id,p),(0,u.eq)(d.tenantId,i)));if(!I)throw new Error(`Group not found in tenant: ${p}`)}function k(r,i){return{linkId:Number(r.linkId),groupId:Number(r.groupId),tenantId:String(r.tenantId),provider:String(r.provider),externalId:String(r.externalId),externalKey:String(r.externalKey),membershipMode:K(String(r.membershipMode)),isSyncEnabled:!!r.isSyncEnabled,...r.syncedAt?{syncedAt:new Date(r.syncedAt).toISOString()}:{},...r.syncError?{syncError:String(r.syncError)}:{},unresolvedCount:i}}async function _(r,i){let p=await r.select({groupId:h.groupId,n:(0,u.count)()}).from(h).innerJoin(d,(0,u.and)((0,u.eq)(d.id,h.groupId),(0,u.eq)(d.tenantId,i))).where((0,u.isNull)(h.resolvedUserId)).groupBy(h.groupId);return new Map(p.map(I=>[Number(I.groupId),Number(I.n)]))}return{async listLinks(r){(0,x.assertTenantId)(r,"listLinks(tenantId)"),await a();let i=await s.select({linkId:n.id,groupId:n.groupId,tenantId:n.tenantId,provider:n.provider,externalId:n.externalId,externalKey:n.externalKey,membershipMode:n.membershipMode,isSyncEnabled:n.isSyncEnabled,syncedAt:n.syncedAt,syncError:n.syncError}).from(n).where((0,u.eq)(n.tenantId,r)).orderBy((0,u.asc)(n.groupId)),p=await _(s,r);return i.map(I=>((0,x.assertTenantMatch)(r,String(I.tenantId),"listLinks(row.tenantId)"),k(I,p.get(Number(I.groupId))??0)))},async externalGroupKey(r,i){(0,x.assertTenantId)(r,"externalGroupKey(tenantId)"),await a();let[p]=await s.select({externalKey:n.externalKey}).from(n).where((0,u.and)((0,u.eq)(n.groupId,i),(0,u.eq)(n.tenantId,r)));return p?String(p.externalKey):null},async linkGroup(r,i,p,I){(0,x.assertTenantId)(r,"linkGroup(tenantId)");let D=K(p.membershipMode),G=p.externalId.trim(),E=(0,O.normalizeAuthEmail)(p.externalKey);if(G===""||E==="")throw new TypeError("[@aiquants/auth-directory-drizzle] externalId and externalKey must be non-empty");await a(),await g.linkable.assertLinkable(r,i),await s.transaction(async q=>{await T(q,r,i),await w(q,r,i),await q.insert(n).output().values({groupId:i,tenantId:r,provider:p.provider,externalId:G,externalKey:E,membershipMode:D,isSyncEnabled:!0,vanishedObservations:0,createdAt:new Date,createdBy:I})}),f(r)},async unlinkGroup(r,i){(0,x.assertTenantId)(r,"unlinkGroup(tenantId)"),await a(),await s.transaction(async p=>{await T(p,r,i),await p.delete(h).where((0,u.eq)(h.groupId,i)),await p.delete(l).where((0,u.and)((0,u.eq)(l.groupId,i),(0,u.eq)(l.tenantId,r))),await p.delete(n).where((0,u.and)((0,u.eq)(n.groupId,i),(0,u.eq)(n.tenantId,r)))}),f(r)},async setSyncEnabled(r,i,p,I){(0,x.assertTenantId)(r,"setSyncEnabled(tenantId)"),await a(),await s.update(n).set({isSyncEnabled:p,updatedAt:new Date,updatedBy:I}).output().where((0,u.and)((0,u.eq)(n.groupId,i),(0,u.eq)(n.tenantId,r)))},async requestSync(r,i,p){(0,x.assertTenantId)(r,"requestSync(tenantId)"),await a(),await s.transaction(async I=>{i!==null&&await T(I,r,i),await I.insert(S).output().values({tenantId:r,groupId:i,requestedBy:p,requestedAt:new Date,createdAt:new Date,createdBy:p})})},async getStatus(r){(0,x.assertTenantId)(r,"getStatus(tenantId)"),await a();let i=await s.select({groupId:n.groupId,isSyncEnabled:n.isSyncEnabled,syncedAt:n.syncedAt,syncError:n.syncError}).from(n).where((0,u.eq)(n.tenantId,r)),[p]=await s.select({n:(0,u.count)()}).from(S).where((0,u.and)((0,u.eq)(S.tenantId,r),(0,u.isNull)(S.finishedAt))),I=i.filter(R=>!!R.isSyncEnabled),D=I.map(R=>R.syncedAt?new Date(R.syncedAt).getTime():null),G=D.length>0&&D.every(R=>R!==null)?Math.min(...D):null,q=i.length>0&&I.length===0||I.length>0&&(G===null||Date.now()-G>g.stalenessThresholdSec*1e3);return{isEnabled:g.isEnabled,linkedGroupCount:i.length,...G!==null?{oldestSyncedAt:new Date(G).toISOString()}:{},isStale:q,pausedGroupCount:i.length-I.length,stalenessThresholdSec:g.stalenessThresholdSec,erroredGroupIds:i.filter(R=>!!R.syncError).map(R=>Number(R.groupId)).sort((R,de)=>R-de),pendingRequestCount:Number(p?.n??0)}},async loadTenantMembershipPolicy(r){(0,x.assertTenantId)(r,"loadTenantMembershipPolicy(tenantId)");let i=m>0?b.get(r):void 0;if(i&&Date.now()-i.loadedAt<m)return i.policy;await a();let p=await s.select({groupId:e.groupId,isBreakGlass:e.isBreakGlass,externalLinkId:n.id}).from(e).innerJoin(d,(0,u.and)((0,u.eq)(d.id,e.groupId),(0,u.eq)(d.tenantId,r))).leftJoin(n,(0,u.eq)(n.groupId,e.groupId)).where((0,u.eq)(e.tenantId,r));if(p.length===0){let E={kind:"no-proof-required"};return m>0&&b.set(r,{policy:E,loadedAt:Date.now()}),E}let I=p.map(E=>Number(E.groupId)),D=p.filter(E=>!!E.isBreakGlass);for(let E of D)if(E.externalLinkId!==null)throw new Error(`Break-glass group ${Number(E.groupId)} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`);let G={kind:"require-proof",proofGroupIds:I,breakGlassGroupIds:D.map(E=>Number(E.groupId))};return(0,ne.assertTenantMembershipPolicy)(G,`tenant ${r}`),m>0&&b.set(r,{policy:G,loadedAt:Date.now()}),G},async setTenantMembershipGroup(r,i,p,I){(0,x.assertTenantId)(r,"setTenantMembershipGroup(tenantId)"),await a(),await s.transaction(async D=>{if(await T(D,r,i),p){let[E]=await D.select({id:n.id}).from(n).where((0,u.and)((0,u.eq)(n.tenantId,r),(0,u.eq)(n.groupId,i)));if(E)throw new Error(`Group ${i} is externally sourced; a break-glass proof path must be one the synchronization can never touch.`)}if((await D.select({groupId:e.groupId}).from(e).where((0,u.and)((0,u.eq)(e.tenantId,r),(0,u.eq)(e.groupId,i)))).length>0){await D.update(e).set({isBreakGlass:p,updatedAt:new Date,updatedBy:I}).output().where((0,u.and)((0,u.eq)(e.tenantId,r),(0,u.eq)(e.groupId,i))),f(r);return}await D.insert(e).output().values({tenantId:r,groupId:i,isBreakGlass:p,createdAt:new Date,createdBy:I})}),f(r)},async removeTenantMembershipGroup(r,i){(0,x.assertTenantId)(r,"removeTenantMembershipGroup(tenantId)"),await a(),await s.transaction(async p=>{let D=(await p.select({groupId:e.groupId,isBreakGlass:e.isBreakGlass}).from(e).where((0,u.eq)(e.tenantId,r))).filter(G=>Number(G.groupId)!==i);if(D.length>0&&!D.some(G=>!!G.isBreakGlass))throw new Error(`Removing group ${i} would leave tenant ${r} with a membership proof but no break-glass path.`);await p.delete(e).where((0,u.and)((0,u.eq)(e.tenantId,r),(0,u.eq)(e.groupId,i)))}),f(r)},async setGroupActive(r,i,p,I){(0,x.assertTenantId)(r,"setGroupActive(tenantId)"),await a(),await s.update(d).set({isActive:p,updatedAt:new Date,updatedBy:I}).output().where((0,u.and)((0,u.eq)(d.id,i),(0,u.eq)(d.tenantId,r)))},async listLedgerGroupIds(r,i){if((0,x.assertTenantId)(r,"listLedgerGroupIds(tenantId)"),!g.isEnabled)return[];await a();let p=await z(s,{ledger:h,group:d},{tenantId:r,externalUserId:i.externalUserId?.trim()||null,email:(0,O.normalizeAuthEmail)(i.email)});return[...new Set(p.map(I=>I.groupId))].sort((I,D)=>I-D)},async isEmailAllowedByGroup(r){if(!g.isEnabled)return!1;let i=(0,O.normalizeAuthEmail)(r);if(i==="")return!1;await a();let[p]=await s.select({id:h.id}).from(h).innerJoin(l,(0,u.eq)(l.groupId,h.groupId)).innerJoin(d,(0,u.and)((0,u.eq)(d.id,h.groupId),(0,u.eq)(d.isActive,!0))).where((0,u.eq)(h.email,i));return!!p},async listAllowlistGroups(r){return(0,x.assertTenantId)(r,"listAllowlistGroups(tenantId)"),await a(),(await s.select({id:l.id,groupId:l.groupId,groupKey:d.groupKey,groupName:d.name,description:l.description}).from(l).innerJoin(d,(0,u.and)((0,u.eq)(d.id,l.groupId),(0,u.eq)(d.tenantId,r))).where((0,u.eq)(l.tenantId,r)).orderBy((0,u.asc)(d.name))).map(p=>({id:Number(p.id),type:"group",groupId:Number(p.groupId),groupKey:String(p.groupKey),groupName:String(p.groupName),...p.description?{description:String(p.description)}:{},owner:{kind:"tenant",tenantId:r},readOnly:!1}))},async addAllowlistGroup(r,i,p,I){(0,x.assertTenantId)(r,"addAllowlistGroup(tenantId)"),await a(),await s.transaction(async D=>{await T(D,r,i);let[G]=await D.select({id:n.id}).from(n).where((0,u.and)((0,u.eq)(n.groupId,i),(0,u.eq)(n.tenantId,r)));if(!G)throw new Error(`Group ${i} is locally managed; only externally-sourced groups can gate sign-in, because the decision reads the upstream member ledger.`);await D.insert(l).output().values({tenantId:r,groupId:i,description:p??null,createdAt:new Date,createdBy:I})})},async removeAllowlistGroup(r,i){(0,x.assertTenantId)(r,"removeAllowlistGroup(tenantId)"),await a(),await s.delete(l).where((0,u.and)((0,u.eq)(l.id,i),(0,u.eq)(l.tenantId,r)))},async countProjectedMembers(r,i){(0,x.assertTenantId)(r,"countProjectedMembers(tenantId)"),await a();let[p]=await s.select({n:(0,u.count)()}).from(v).innerJoin(d,(0,u.and)((0,u.eq)(d.id,v.groupId),(0,u.eq)(d.tenantId,r))).where((0,u.eq)(v.groupId,i));return Number(p?.n??0)}}}var oe=require("@aiquants/auth-core"),C=require("@aiquants/authz-core");async function we(t,o){let y=(0,C.assertTenantId)(o.tenantId,"promoteLedgerForUser(tenantId)");if(!Number.isInteger(o.userId)||o.userId<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] userId must be a positive integer, received ${String(o.userId)}`);let g=(0,oe.normalizeAuthEmail)(o.email),s=o.externalUserId?.trim()||null;if(s===null&&g==="")return{addedGroupIds:[],matchedLedgerIds:[]};let a=await t.findLedgerMatches({tenantId:y,externalUserId:s,email:g});if(a.length===0)return{addedGroupIds:[],matchedLedgerIds:[]};for(let n of a)(0,C.assertTenantMatch)(y,n.tenantId,"promoteLedgerForUser(findLedgerMatches row)");let m=[...new Set(a.map(n=>n.ledgerId))].sort((n,h)=>n-h),b=[...new Set(a.map(n=>n.groupId))].sort((n,h)=>n-h);return{addedGroupIds:[...await t.attachUserToGroups({tenantId:y,userId:o.userId,ledgerIds:m,groupIds:b})].sort((n,h)=>n-h),matchedLedgerIds:m}}var W=require("@aiquants/authz-core"),M=require("drizzle-orm");var ie=2100;var qe=500;function L(t,o=500){if(!Number.isInteger(o)||o<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] chunk size must be a positive integer, received ${String(o)}`);let y=[];for(let g=0;g<t.length;g+=o)y.push(t.slice(g,g+o));return y}function N(t,o,y=100){if(!Number.isInteger(o)||o<=0)throw new TypeError(`[@aiquants/auth-directory-drizzle] parametersPerItem must be a positive integer, received ${String(o)}`);if(!Number.isInteger(y)||y<0)throw new TypeError(`[@aiquants/auth-directory-drizzle] reservedParameters must be a non-negative integer, received ${String(y)}`);let g=2100-y,s=Math.floor(g/o);if(s<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] a single item binds ${o} parameters, which exceeds the ${g} available in one statement`);return L(t,s)}var Ie=4,Se=100;function Ae(t,o,y,g){let s=t,a=g.ensureConnection??(async()=>{}),m=g.now??(()=>new Date),b=o.TDGroupMemberEmail,{TMGroup:f,TDGroupMember:n}=y;return{async findLedgerMatches(h){return(0,W.assertTenantId)(h.tenantId,"findLedgerMatches(tenantId)"),await a(),z(s,{ledger:b,group:f},h)},async attachUserToGroups({tenantId:h,userId:e,ledgerIds:l,groupIds:S}){return(0,W.assertTenantId)(h,"attachUserToGroups(tenantId)"),await a(),l.length===0?[]:s.transaction(async d=>{let v=new Set;for(let r of L(S)){let i=await d.select({id:f.id}).from(f).where((0,M.and)((0,M.inArray)(f.id,r),(0,M.eq)(f.tenantId,h),(0,M.eq)(f.isActive,!0)));for(let p of i)v.add(Number(p.id))}let w=S.filter(r=>v.has(r));if(w.length===0)return[];let T=new Set;for(let r of L(w)){let i=await d.select({groupId:n.groupId}).from(n).where((0,M.and)((0,M.eq)(n.userId,e),(0,M.inArray)(n.groupId,r)));for(let p of i)T.add(Number(p.groupId))}let k=w.filter(r=>!T.has(r)),_=Math.max(1,2100-Se-w.length);for(let r of L(l,_))await d.update(b).set({resolvedUserId:e}).output().where((0,M.and)((0,M.inArray)(b.id,r),(0,M.inArray)(b.groupId,w)));if(k.length>0){let r=m();for(let i of N(k,Ie))await d.insert(n).output().values(i.map(p=>({groupId:p,userId:e,createdAt:r,createdBy:g.actor})))}return k})}}}var U=require("@aiquants/authz-drizzle"),c=require("drizzle-orm/mssql-core"),se="provider",ve=["TDGroupExternalLink","TDTenantMembershipGroup","TDAllowlistGroup","TDDirectorySyncRequest","TMAllowlist"];function Te(t,o){let y=(0,c.mssqlSchema)(t),g=()=>({createdAt:(0,c.datetime2)("created_at"),createdBy:(0,c.nvarchar)("created_by",{length:50}),updatedAt:(0,c.datetime2)("updated_at"),updatedBy:(0,c.nvarchar)("updated_by",{length:50})}),s=()=>({createdAt:(0,c.datetime2)("created_at"),createdBy:(0,c.nvarchar)("created_by",{length:50})}),a=y.table("TDGroupExternalLink",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}).notNull(),tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),provider:(0,c.nvarchar)(se,{length:32}).notNull(),externalId:(0,c.nvarchar)("external_id",{length:256}).notNull(),externalKey:(0,c.nvarchar)("external_key",{length:320}).notNull(),membershipMode:(0,c.nvarchar)("membership_mode",{length:16}).notNull(),isSyncEnabled:(0,c.bit)("is_sync_enabled").notNull(),syncedAt:(0,c.datetime2)("synced_at"),syncError:(0,c.nvarchar)("sync_error",{length:1e3}),vanishedObservations:(0,c.int)("vanished_observations").notNull(),...g()},e=>[(0,c.primaryKey)({name:`${t}_TDGroupExternalLink_pk`,columns:[e.id]}),(0,c.uniqueIndex)(`${t}_TDGroupExternalLink_group_uq`).on(e.groupId),(0,c.uniqueIndex)(`${t}_TDGroupExternalLink_external_uq`).on(e.tenantId,e.provider,e.externalId),(0,c.foreignKey)({name:`${t}_TDGroupExternalLink_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),m=y.table("TDGroupMemberEmail",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}).notNull(),email:(0,c.nvarchar)("email",{length:320}).notNull(),externalUserId:(0,c.nvarchar)("external_user_id",{length:128}),resolvedUserId:(0,c.bigint)("resolved_user_id",{mode:"number"}),observedAt:(0,c.datetime2)("observed_at").notNull(),...g()},e=>[(0,c.primaryKey)({name:`${t}_TDGroupMemberEmail_pk`,columns:[e.id]}),(0,c.uniqueIndex)(`${t}_TDGroupMemberEmail_group_email_uq`).on(e.groupId,e.email),(0,c.foreignKey)({name:`${t}_TDGroupMemberEmail_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),b=y.table("TDTenantMembershipGroup",{tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}).notNull(),isBreakGlass:(0,c.bit)("is_break_glass").notNull(),...s()},e=>[(0,c.primaryKey)({name:`${t}_TDTenantMembershipGroup_pk`,columns:[e.tenantId,e.groupId]}),(0,c.foreignKey)({name:`${t}_TDTenantMembershipGroup_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),f=y.table("TDAllowlistGroup",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}).notNull(),description:(0,c.nvarchar)("description",{length:512}),...s()},e=>[(0,c.primaryKey)({name:`${t}_TDAllowlistGroup_pk`,columns:[e.id]}),(0,c.uniqueIndex)(`${t}_TDAllowlistGroup_tenant_group_uq`).on(e.tenantId,e.groupId),(0,c.foreignKey)({name:`${t}_TDAllowlistGroup_group_id_fk`,columns:[e.groupId],foreignColumns:[o.groupTable.id]})]),n=y.table("TDDirectorySyncRequest",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),groupId:(0,c.bigint)("group_id",{mode:"number"}),requestedBy:(0,c.nvarchar)("requested_by",{length:320}).notNull(),requestedAt:(0,c.datetime2)("requested_at").notNull(),pickedAt:(0,c.datetime2)("picked_at"),finishedAt:(0,c.datetime2)("finished_at"),result:(0,c.nvarchar)("result",{length:32}),error:(0,c.nvarchar)("error",{length:2e3}),...s()},e=>[(0,c.primaryKey)({name:`${t}_TDDirectorySyncRequest_pk`,columns:[e.id]})]),h=y.table("TMAllowlist",{id:(0,c.bigint)("id",{mode:"number"}).identity().notNull(),tenantId:(0,c.nvarchar)(U.AUTHZ_TENANT_COLUMN,{length:64}).notNull(),pattern:(0,c.nvarchar)("pattern",{length:256}).notNull(),type:(0,c.nvarchar)("type",{length:32}).notNull(),description:(0,c.nvarchar)("description",{length:512}),...s()},e=>[(0,c.primaryKey)({name:`${t}_TMAllowlist_pk`,columns:[e.id]}),(0,c.uniqueIndex)(`${t}_TMAllowlist_pattern_uq`).on(e.tenantId,e.pattern)]);return{TDGroupExternalLink:a,TDGroupMemberEmail:m,TDTenantMembershipGroup:b,TDAllowlistGroup:f,TDDirectorySyncRequest:n,TMAllowlist:h}}var j=require("@aiquants/auth-directory-core");var X=(t,o=20)=>t.length<=o?t.join(", "):`${t.slice(0,o).join(", ")} \u307B\u304B ${t.length-o} \u4EF6`,Q={upstreamUnreadable:t=>`\u4E0A\u6D41\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8AAD\u307F\u53D6\u308A\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${t}`,localWriteFailed:t=>`\u30ED\u30FC\u30AB\u30EB\u3078\u306E\u66F8\u304D\u8FBC\u307F\u306B\u5931\u6557\u3057\u307E\u3057\u305F: ${t}`,resolverIncomplete:(t,o)=>`\u4E0A\u6D41\u304C ${t} \u4EF6\u306E\u30E1\u30F3\u30D0\u30FC\u3092\u8FD4\u3057\u307E\u3057\u305F\u304C\u3001\u7A81\u5408\u7D50\u679C\u306F ${o} \u4EF6\u3067\u3057\u305F\u3002\u4EF6\u6570\u304C\u6E1B\u308B\u7A81\u5408\u306F\u3001\u89E3\u6C7A\u3067\u304D\u306A\u304B\u3063\u305F\u4EBA\u7269\u3092\u300C\u4E0A\u6D41\u304B\u3089\u6D88\u3048\u305F\u300D\u3068\u3057\u3066\u524A\u9664\u3057\u3066\u3057\u307E\u3046\u305F\u3081\u4E2D\u65AD\u3057\u307E\u3057\u305F\u3002\u89E3\u6C7A\u3067\u304D\u306A\u3044\u30E1\u30F3\u30D0\u30FC\u306F\u7701\u7565\u305B\u305A resolvedUserId: null \u3067\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002`,groupMissing:(t,o,y)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093 (${t})\u3002\u9023\u7D9A ${o} \u56DE\u76EE\u3067\u3059\u3002${y} \u56DE\u306B\u9054\u3057\u305F\u6642\u70B9\u3067\u30B0\u30EB\u30FC\u30D7\u3092\u7121\u52B9\u5316\u3057\u307E\u3059\u3002`,groupVanished:(t,o)=>`\u4E0A\u6D41\u3067\u30B0\u30EB\u30FC\u30D7\u304C ${o} \u56DE\u9023\u7D9A\u3067\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F (${t})\u3002\u30B0\u30EB\u30FC\u30D7\u3092\u7121\u52B9\u5316\u3057\u307E\u3057\u305F\u3002\u4E0A\u6D41\u304C\u5FA9\u65E7\u3059\u308C\u3070\u6B21\u56DE\u306E\u540C\u671F\u3067\u81EA\u52D5\u7684\u306B\u518D\u6709\u52B9\u5316\u3055\u308C\u307E\u3059\u3002`,planRefused:t=>{if(t.reason==="invalid-upstream-data")return`\u540C\u671F\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F: \u4E0A\u6D41\u306E\u30E1\u30F3\u30D0\u30FC\u4E00\u89A7\u306B\u6271\u3048\u306A\u3044\u30A2\u30C9\u30EC\u30B9\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059 (${X(t.offendingEmails)})\u3002`;let o=t.axis==="membership"?"\u6A29\u9650\u3092\u5931\u3046\u4EBA\u6570":"\u30B5\u30A4\u30F3\u30A4\u30F3\u3067\u304D\u306A\u304F\u306A\u308B\u4EBA\u6570",y=t.axis==="membership"?t.withheldProjectionRemoves.map(String):t.withheldLedgerDeletes;return[`\u540C\u671F\u3092\u4E2D\u65AD\u3057\u307E\u3057\u305F: ${o}\u304C ${t.population} \u4EBA\u4E2D ${t.removalCount} \u4EBA\u306B\u306A\u308A\u307E\u3059`,`(\u4E0A\u9650: ${t.limits.maxRemovalCount} \u4EF6 / \u6BD4\u7387 ${t.limits.maxRemovalRatio})\u3002`,`\u5DEE\u3057\u6B62\u3081\u305F\u5BFE\u8C61: ${X(y)}\u3002`,"\u4E0A\u6D41\u5074\u306E\u8A2D\u5B9A\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u610F\u56F3\u3057\u305F\u5909\u66F4\u3067\u3042\u308C\u3070\u3001\u3053\u306E\u8EF8\u306E\u4E0A\u9650\u3060\u3051\u3092\u4E00\u6642\u7684\u306B\u5F15\u304D\u4E0A\u3052\u3066\u518D\u5B9F\u884C\u3057\u307E\u3059\u3002"].join(" ")},removalsRefused:t=>`${t.length} \u4EF6\u306E\u6240\u5C5E\u89E3\u9664\u304C\u6700\u5F8C\u306E\u7BA1\u7406\u8005\u30AC\u30FC\u30C9\u306B\u3088\u308A\u62D2\u5426\u3055\u308C\u307E\u3057\u305F (\u30E6\u30FC\u30B6\u30FC ${X(t.map(o=>String(o.userId)))})\u3002\u6B8B\u308A\u306E\u5909\u66F4\u306F\u9069\u7528\u6E08\u307F\u3067\u3059\u3002`,foreignProvider:(t,o)=>`\u3053\u306E\u30EA\u30F3\u30AF\u306E\u4F9B\u7D66\u5143\u306F ${t} \u3067\u3059\u304C\u3001\u5B9F\u884C\u4E2D\u306E\u540C\u671F\u306F ${o} \u7528\u3067\u3059\u3002\u5BFE\u5FDC\u3059\u308B\u540C\u671F\u30B8\u30E7\u30D6\u304B\u3089\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002`};var Z=["aborted","missing","vanished","upstream-failed","local-failed","foreign-provider"];function De(t){let{directory:o,repository:y,policy:g,now:s,logger:a}=t,m=t.messages??Q;if((0,j.assertBlastRadiusPolicy)(g),!Number.isInteger(t.vanishedThreshold)||t.vanishedThreshold<1)throw new TypeError(`[@aiquants/auth-directory-drizzle] vanishedThreshold must be a positive integer, received ${String(t.vanishedThreshold)}`);if(typeof t.provider!="string"||t.provider.trim()==="")throw new TypeError("[@aiquants/auth-directory-drizzle] provider must be a non-empty string so links of other providers can be told apart");async function b(e,l){try{await y.recordFailure(e,l)}catch(S){a.error(`[auth-directory] could not record the failure for ${e.externalKey}:`,S)}}async function f(e){try{let l=await o.getGroup(e.externalId);return l===null?{kind:"missing"}:{kind:"ok",group:l,members:await o.listGroupMembers(l,e.membershipMode)}}catch(l){return{kind:"failed",error:l instanceof Error?l:new Error(String(l))}}}async function n(e){let l=await y.recordVanishedObservation(e,m.groupMissing(e.externalKey,e.vanishedObservations+1,t.vanishedThreshold));return l<t.vanishedThreshold?(a.warn(`[auth-directory] ${e.externalKey} missing upstream (${l}/${t.vanishedThreshold})`),{kind:"missing",link:e,observations:l}):(await y.markGroupInactive(e),await b(e,m.groupVanished(e.externalKey,l)),a.warn(`[auth-directory] ${e.externalKey} deactivated after ${l} consecutive absences`),{kind:"vanished",link:e})}async function h(e){if(e.provider!==t.provider)return await b(e,m.foreignProvider(e.provider,t.provider)),a.warn(`[auth-directory] skipping ${e.externalKey}: belongs to provider ${e.provider}`),{kind:"foreign-provider",link:e};let l=await f(e);if(l.kind==="missing")return n(e);if(l.kind==="failed")return await b(e,m.upstreamUnreadable(l.error.message)),a.error(`[auth-directory] upstream read failed for ${e.externalKey}:`,l.error),{kind:"upstream-failed",link:e,error:l.error};try{let[S,d]=await Promise.all([y.loadGroupSnapshot(e),y.resolveMembers(l.members)]);if(d.length!==l.members.length){let _=m.resolverIncomplete(l.members.length,d.length);return await b(e,_),a.error(`[auth-directory] ${_}`),{kind:"local-failed",link:e,error:new Error(_)}}let v=(0,j.reconcile)(S,d,g);if(v.aborted)return await b(e,m.planRefused(v.aborted)),a.warn(`[auth-directory] plan refused for ${e.externalKey}: ${v.aborted.reason}`),{kind:"aborted",link:e,plan:v};let w=v.ledgerUpserts.length>0||v.ledgerDeletes.length>0||v.projectionAdds.length>0||v.projectionRemoves.length>0,T=s(),k={refusals:[]};return w&&(k=await y.applyPlan(e,v,T)),await y.recordSuccess(e,l.group,T),k.refusals.length>0&&(await b(e,m.removalsRefused(k.refusals)),a.warn(`[auth-directory] ${k.refusals.length} removal(s) refused for ${e.externalKey}`)),v.unresolvedEmails.length>0&&a.info(`[auth-directory] ${e.externalKey}: ${v.unresolvedEmails.length} upstream member(s) have no local user yet`),w?{kind:"applied",link:e,plan:v}:{kind:"unchanged",link:e}}catch(S){let d=S instanceof Error?S:new Error(String(S));return await b(e,m.localWriteFailed(d.message)),a.error(`[auth-directory] local write failed for ${e.externalKey}:`,d),{kind:"local-failed",link:e,error:d}}}return{syncOne:h,async run(e={}){let l=await y.listSyncableLinks(e),S=[];for(let v of l)try{S.push(await h(v))}catch(w){let T=w instanceof Error?w:new Error(String(w));a.error(`[auth-directory] ${v.externalKey} ended abnormally:`,T),S.push({kind:"local-failed",link:v,error:T})}let d=S.filter(v=>Z.includes(v.kind)).length;return a.info(`[auth-directory] run finished: ${S.length} link(s), ${d} unhealthy`),{outcomes:S,unhealthyCount:d}}}}var ae=require("@aiquants/authz-core"),P=require("drizzle-orm"),ee=2e3;function xe(t,o,y){let g=t,s=y.ensureConnection??(async()=>{}),a=o.TDDirectorySyncRequest,m=y.maxErrorLength??ee;if(!Number.isInteger(m)||m<1||m>ee)throw new TypeError(`[@aiquants/auth-directory-drizzle] maxErrorLength must be an integer within 1..${ee}, received ${String(y.maxErrorLength)}`);return{async claim(){await s();let b=await g.select({id:a.id}).from(a).where((0,P.isNull)(a.pickedAt)).orderBy((0,P.asc)(a.id));for(let f of b){let h=(await g.update(a).set({pickedAt:y.now()}).output().where((0,P.and)((0,P.eq)(a.id,Number(f.id)),(0,P.isNull)(a.pickedAt))))?.[0];if(!h)continue;let e=String(h.tenant_id??h.tenantId??""),l=h.group_id??h.groupId??null;return{id:Number(h.id),tenantId:(0,ae.assertTenantId)(e,"claim(row.tenantId)"),groupId:l===null?null:Number(l),requestedBy:String(h.requested_by??h.requestedBy??"")}}return null},async finish(b,f){await s();let n=f.error?f.error.slice(0,m):null;await g.update(a).set({finishedAt:y.now(),result:f.result,error:n}).output().where((0,P.eq)(a.id,b))},async listStranded(b){return await s(),(await g.select({id:a.id,pickedAt:a.pickedAt}).from(a).where((0,P.isNull)(a.finishedAt)).orderBy((0,P.asc)(a.id))).filter(n=>n.pickedAt!==null&&new Date(n.pickedAt)<b).map(n=>Number(n.id))}}}var re=require("@aiquants/auth-core"),B=require("@aiquants/authz-core"),A=require("drizzle-orm");var Ge=7,ke=4;function Ee(t,o,y,g){let s=t,a=g.ensureConnection??(async()=>{}),{TDGroupExternalLink:m,TDGroupMemberEmail:b}=o,{TMGroup:f,TDGroupMember:n}=y,h=g.actor;return{async listSyncableLinks(e){await a();let l=[(0,A.eq)(m.isSyncEnabled,!0)];return e.tenantId!==void 0&&l.push((0,A.eq)(m.tenantId,(0,B.assertTenantId)(e.tenantId,"listSyncableLinks(tenantId)"))),e.groupId!==void 0&&l.push((0,A.eq)(m.groupId,e.groupId)),(await s.select({linkId:m.id,groupId:m.groupId,linkTenantId:m.tenantId,groupTenantId:f.tenantId,groupKey:f.groupKey,isGroupActive:f.isActive,provider:m.provider,externalId:m.externalId,externalKey:m.externalKey,membershipMode:m.membershipMode,vanishedObservations:m.vanishedObservations}).from(m).innerJoin(f,(0,A.eq)(f.id,m.groupId)).where((0,A.and)(...l))).map(d=>((0,B.assertTenantMatch)(String(d.groupTenantId),String(d.linkTenantId),"listSyncableLinks(link.tenantId vs TMGroup.tenant_id)"),{linkId:Number(d.linkId),groupId:Number(d.groupId),groupKey:String(d.groupKey),tenantId:String(d.groupTenantId),provider:String(d.provider),externalId:String(d.externalId),externalKey:String(d.externalKey),membershipMode:K(String(d.membershipMode)),isGroupActive:!!d.isGroupActive,vanishedObservations:Number(d.vanishedObservations??0)}))},async loadGroupSnapshot(e){await a();let[l,S]=await Promise.all([s.select({email:b.email,externalUserId:b.externalUserId,resolvedUserId:b.resolvedUserId}).from(b).where((0,A.eq)(b.groupId,e.groupId)),s.select({userId:n.userId}).from(n).where((0,A.eq)(n.groupId,e.groupId))]);return{ledger:l.map(d=>({email:String(d.email),...d.externalUserId?{externalUserId:String(d.externalUserId)}:{},resolvedUserId:d.resolvedUserId===null?null:Number(d.resolvedUserId)})),projectedUserIds:S.map(d=>Number(d.userId))}},resolveMembers(e){return g.memberResolver.resolve(e)},async applyPlan(e,l,S){(0,B.assertTenantId)(e.tenantId,"applyPlan(link.tenantId)"),await a(),(l.ledgerUpserts.length>0||l.projectionAdds.length>0)&&await s.transaction(async w=>{let T=l.ledgerUpserts.map(r=>({...r,email:(0,re.normalizeAuthEmail)(r.email)})),k=new Map;for(let r of L(T.map(i=>i.email))){let i=await w.select({id:b.id,email:b.email}).from(b).where((0,A.and)((0,A.eq)(b.groupId,e.groupId),(0,A.inArray)(b.email,r)));for(let p of i)k.set(String(p.email),Number(p.id))}let _=T.filter(r=>!k.has(r.email));for(let r of N(_,Ge))await w.insert(b).output().values(r.map(i=>({groupId:e.groupId,email:i.email,externalUserId:i.externalUserId??null,resolvedUserId:i.resolvedUserId,observedAt:S,createdAt:S,createdBy:h})));for(let r of T){let i=k.get(r.email);i!==void 0&&await w.update(b).set({externalUserId:r.externalUserId??null,resolvedUserId:r.resolvedUserId,observedAt:S,updatedAt:S,updatedBy:h}).output().where((0,A.eq)(b.id,i))}for(let r of N(l.projectionAdds,ke)){let i=new Set((await w.select({userId:n.userId}).from(n).where((0,A.and)((0,A.eq)(n.groupId,e.groupId),(0,A.inArray)(n.userId,r)))).map(I=>Number(I.userId))),p=r.filter(I=>!i.has(I));p.length>0&&await w.insert(n).output().values(p.map(I=>({groupId:e.groupId,userId:I,createdAt:S,createdBy:h})))}});let d=[];for(let w of l.projectionRemoves)try{await g.lockoutGuard.guardedWrite(e.tenantId,{removeGroupMembership:{groupId:e.groupId,userId:w}},"remove-group-member",T=>T.delete(n).where((0,A.and)((0,A.eq)(n.groupId,e.groupId),(0,A.eq)(n.userId,w))))}catch(T){d.push({userId:w,applied:!1,refusal:T instanceof Error?T.message:String(T)})}let v=d.map(w=>w.userId);return l.ledgerDeletes.length>0&&await s.transaction(async w=>{for(let T of L(l.ledgerDeletes)){let k=v.length>0?(0,A.or)((0,A.isNull)(b.resolvedUserId),(0,A.notInArray)(b.resolvedUserId,v)):void 0;await w.delete(b).where((0,A.and)((0,A.eq)(b.groupId,e.groupId),(0,A.inArray)(b.email,T),...k?[k]:[]))}}),{refusals:d}},async recordSuccess(e,l,S){await a(),await s.transaction(async d=>{await d.update(m).set({syncedAt:S,syncError:null,vanishedObservations:0,externalId:l.externalId,externalKey:(0,re.normalizeAuthEmail)(l.externalKey),updatedAt:S,updatedBy:h}).output().where((0,A.eq)(m.id,e.linkId)),e.isGroupActive||await d.update(f).set({isActive:!0,updatedAt:S,updatedBy:h}).output().where((0,A.and)((0,A.eq)(f.id,e.groupId),(0,A.eq)(f.tenantId,e.tenantId)))})},async recordFailure(e,l){await a(),await s.update(m).set({syncError:l.slice(0,1e3),updatedAt:new Date,updatedBy:h}).output().where((0,A.eq)(m.id,e.linkId))},async recordVanishedObservation(e,l){await a();let S=e.vanishedObservations+1;return await s.update(m).set({vanishedObservations:S,syncError:l.slice(0,1e3),updatedAt:new Date,updatedBy:h}).output().where((0,A.eq)(m.id,e.linkId)),S},async markGroupInactive(e){await a(),await s.update(f).set({isActive:!1,updatedAt:new Date,updatedBy:h}).output().where((0,A.and)((0,A.eq)(f.id,e.groupId),(0,A.eq)(f.tenantId,e.tenantId)))}}}0&&(module.exports={AUTH_DIRECTORY_PROVIDER_COLUMN,AUTH_DIRECTORY_TENANT_SCOPED_TABLES,MAX_IN_LIST,MAX_PARAMETERS,MEMBERSHIP_MODES,UNHEALTHY_SYNC_OUTCOMES,assertGroupMayBeLinked,assertMembershipMode,chunk,chunkByParameters,createDirectoryLinkStore,createDirectorySync,createDirectorySyncRepository,createPromotionRepository,createSyncRequestQueue,defaultExternalGroupGuardMessage,defaultSyncMessages,defineAuthDirectorySchema,findLedgerRowsForIdentity,promoteLedgerForUser,withExternalGroupGuards});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|