insite-users-server 2.3.1 → 2.3.3

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.
@@ -3,8 +3,28 @@ import { type Ability, type AbilityParam, type AbilityParamItems, type AbilitySc
3
3
  export declare class AbilitiesMap<AS extends AbilitiesSchema> extends Map<string, AbilitySchema> {
4
4
  #private;
5
5
  constructor(abilitiesSchema: AS);
6
- get(longId: string, parent?: AbilitySchema | null): AbilitySchema | undefined;
7
- getSchema: (longId: string, parent?: AbilitySchema | null) => AbilitySchema | undefined;
6
+ get(longId: string, parent?: AbilitySchema | null): {
7
+ _id: string;
8
+ title?: string | undefined;
9
+ description?: string | undefined;
10
+ params?: readonly AbilityParamSchema[] | undefined;
11
+ isInheritable?: boolean | undefined;
12
+ top?: boolean | undefined;
13
+ level: number;
14
+ longId: string;
15
+ abilities?: AbilitySchema[] | undefined;
16
+ } | undefined;
17
+ getSchema: (longId: string, parent?: AbilitySchema | null) => {
18
+ _id: string;
19
+ title?: string | undefined;
20
+ description?: string | undefined;
21
+ params?: readonly AbilityParamSchema[] | undefined;
22
+ isInheritable?: boolean | undefined;
23
+ top?: boolean | undefined;
24
+ level: number;
25
+ longId: string;
26
+ abilities?: AbilitySchema[] | undefined;
27
+ } | undefined;
8
28
  getParamSchema(longId: string, paramId: string): AbilityParamSchema | undefined;
9
29
  getDefaultParam(longId: string, paramId: string, max?: boolean): AbilityParam | undefined;
10
30
  getDefaultParam(schema: AbilityParamSchema, max?: boolean): AbilityParam;
@@ -15,7 +35,17 @@ export declare class AbilitiesMap<AS extends AbilitiesSchema> extends Map<string
15
35
  getDefaultAbilities(schema: AbilitySchema, max?: boolean): Abilities<AS>;
16
36
  getDefaultAbilities(longIds: string[], max?: boolean): Abilities<AS>;
17
37
  getDefaultAbilities(longId: string, max?: boolean): Abilities<AS>;
18
- getSchemeFor(abilities: GenericAbilities): AbilitySchema[];
38
+ getSchemeFor(abilities: GenericAbilities): {
39
+ _id: string;
40
+ title?: string | undefined;
41
+ description?: string | undefined;
42
+ params?: readonly AbilityParamSchema[] | undefined;
43
+ isInheritable?: boolean | undefined;
44
+ top?: boolean | undefined;
45
+ level: number;
46
+ longId: string;
47
+ abilities?: AbilitySchema[] | undefined;
48
+ }[];
19
49
  getParam(abilities: GenericAbilities, longId: string, paramId: string): AbilityParam | undefined;
20
50
  setParam(abilities: GenericAbilities, longId: string, paramId: string, value: AbilityParam): Abilities<AS>;
21
51
  isParamFits(longId: string, paramId: string, value: AbilityParam, referenceValue?: AbilityParam): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"Map.d.ts","sourceRoot":"","sources":["../../src/abilities/Map.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Map.d.ts","sourceRoot":"","sources":["../../src/abilities/Map.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { Prettify } from "@nesvet/n";
1
2
  import type { AbilitySchema as OriginalAbilitySchema } from "insite-common";
2
3
  type AbilityParamItem = string;
3
4
  export type AbilityParamItems = AbilityParamItem[];
@@ -9,11 +10,11 @@ export type AbilityBoolean = true;
9
10
  export type Ability = AbilityBoolean | {
10
11
  [key: string]: Ability | AbilityParam;
11
12
  };
12
- export type AbilitySchema = Omit<OriginalAbilitySchema, "abilities"> & {
13
+ export type AbilitySchema = Prettify<Omit<OriginalAbilitySchema, "abilities"> & {
13
14
  level: number;
14
15
  longId: string;
15
16
  abilities?: AbilitySchema[];
16
- };
17
+ }>;
17
18
  export type GenericAbilities = Record<string, Ability>;
18
19
  export declare function isAbilityObject(value: Ability): value is AbilityObject;
19
20
  export declare function isAbilityParamNumber(value: AbilityParam): value is AbilityParamNumber;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/abilities/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG5E,KAAK,gBAAgB,GAAG,MAAM,CAAC;AAC/B,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,EAAE,CAAC;AACnD,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACxC,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAElE,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAC7D,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,CAAC,CAAC;AACnE,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC;AAClC,MAAM,MAAM,OAAO,GAAG,cAAc,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,YAAY,CAAA;CAAE,CAAC;AAEjF,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,qBAAqB,EAAE,WAAW,CAAC,GAAG;IACtE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEvD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAEtE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,kBAAkB,CAErF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,iBAAiB,CAEnF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/abilities/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,EAAE,aAAa,IAAI,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAG5E,KAAK,gBAAgB,GAAG,MAAM,CAAC;AAC/B,MAAM,MAAM,iBAAiB,GAAG,gBAAgB,EAAE,CAAC;AACnD,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACxC,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAElE,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAC7D,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,YAAY,CAAC,CAAC;AACnE,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC;AAClC,MAAM,MAAM,OAAO,GAAG,cAAc,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,YAAY,CAAA;CAAE,CAAC;AAEjF,MAAM,MAAM,aAAa,GAAG,QAAQ,CACnC,IAAI,CAAC,qBAAqB,EAAE,WAAW,CAAC,GAAG;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B,CACD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEvD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAEtE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,kBAAkB,CAErF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,IAAI,iBAAiB,CAEnF"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{Err as se}from"@nesvet/n";var x=class extends se{constructor(e,i){typeof e=="object"&&(i=e,e=void 0),super("User lacks ability","lacksability",{...e&&{ability:e},...i})}name="AbilityError"};import{add as oe,assignPath as re,deletePath as ne,empty as ae,getPath as F,intersection as le,pick as ce,setPath as de}from"@nesvet/n";function D(l){return typeof l=="object"}function I(l){return typeof l=="number"}function R(l){return Array.isArray(l)}var H=new Map,w=class extends Map{constructor(e){super();for(let i of e)delete i.top,this.#e.push(i);(function i(t,s,o){for(let r of t){if(H.set(r,s),r.level=o,!s||r.top){if(r.longId=r._id,this.has(r._id))throw new Error(`Top-level ability duplicate: ${r._id}`);this.set(r._id,r)}else r.longId=s?`${s.longId}.${r._id}`:r._id;r.abilities&&i.call(this,r.abilities,r,o+1)}}).call(this,e,null,0)}#e=[];get(e,i){let t=e.split("."),s=i??super.get(t.shift());if(s&&t.length){for(let o of t)if(s=s?.abilities?.find(({_id:r,top:a})=>!a&&r===o),!s)break}return s}getSchema=this.get;getParamSchema(e,i){return this.get(e)?.params?.find(({_id:t})=>t===i)}getDefaultParam(e,i,t){(i===void 0||typeof i=="boolean")&&(t=i);let s=typeof e=="string"?this.getParamSchema(e,i):e;if(s)switch(s.type){case"number":return t?s.max??1/0:s.min??0;case"items":return t?s.items.map(({_id:o})=>o):[]}}getDefaultAbility(e,i=!e){if(typeof e=="string"&&(e=this.get(e)),e){if(e.abilities||e.params){let t={};if(e.params)for(let s of e.params)t[s._id]=this.getDefaultParam(s,i);if(i&&e.abilities)for(let s of e.abilities)s.top||(t[s._id]=this.getDefaultAbility(s,i));return t}return!0}}getDefaultAbilities(e,i=!e){let t=(e?(Array.isArray(e)?e:[e]).map(o=>typeof o=="string"?this.get(o):o).filter(Boolean):[...this.values()]).sort((o,r)=>o.level-r.level),s=new Map;for(let o of t)(function r(a){let n=H.get(a);n&&(r(n),s.has(n)||s.set(n,!1))})(o),i?function r(a){if(s.has(a)||s.set(a,!0),a.abilities)for(let n of a.abilities)n.top&&r(n)}(o):s.has(o)||s.set(o,!1);return re({},Object.fromEntries([...s].map(([o,r])=>[o.longId,this.getDefaultAbility(o,r)])))}getSchemeFor(e){return e=this.adjust(structuredClone(e)),function i(t,s){for(let o=0;o<t.length;o++){let r=t[o],a=r.top?e[r._id]:s[r._id];if(a){if(r.params)for(let n of r.params){let d=a[n._id];switch(n.type){case"number":n.max=d;break;case"items":n.items=n.items.filter(({_id:A})=>d.includes(A))}}r.abilities&&(i(r.abilities,a),r.abilities.length||delete r.abilities)}else t.splice(o--,1)}return t}(structuredClone(this.#e),e)}getParam(e,i,t){if(this.getParamSchema(i,t)){let s=F(e,`${i}.${t}`);return this.isParamFits(i,t,s)?s:this.getDefaultParam(i,t)}}setParam(e,i,t,s){let o=this.getParamSchema(i,t);if(!o)throw new Error(`No such ability param: ${i}.${t}`);return de(e,`${i}.${t}`,this.adjustParam(o,s)),e}isParamFits(e,i,t,s){if(t!==void 0){let o=this.getParamSchema(e,i);if(o)switch(o.type){case"number":return I(t)&&(o.min===void 0||t>=o.min)&&(s===void 0?o.max===void 0||t<=o.max:t<=s);case"items":return R(t)&&t.length===new Set(t).size&&(s===void 0?t.every(r=>o.items.find(({_id:a})=>a===r)):t.every(r=>s.includes(r)))}}return!1}adjustParam(e,i){switch(e.type){case"number":return I(i)?Math.max(Math.min(i,e.max??1/0),e.min??0):e.min??0;default:return R(i)?le(e.items.map(t=>t._id),i):[]}}adjust(e,i){let t={};for(let[s,o]of Object.entries(e)){let r=this.get(s,i);if(r)if(r.params||r.abilities){let a={};if(r.params)if(D(o))for(let n of r.params)a[n._id]=this.adjustParam(n,o[n._id]);else for(let n of r.params)a[n._id]=this.getDefaultParam(n);r.abilities&&D(o)&&Object.assign(a,this.adjust(ce(o,r.abilities.filter(n=>!n.top).map(n=>n._id)),r)),t[s]=a}else t[s]=!0}return Object.assign(ae(e),t)}merge(e,i,t){t||(this.adjust(e),i=this.adjust(structuredClone(i)));for(let[s,o]of Object.entries(i)){let r=this.get(s,t);if(r&&r.isInheritable!==!1)if(s in e&&(r.params||r.abilities)){let a=e[s],n=o;if(r.params){for(let d of r.params)if(d.isInheritable!==!1)switch(d.type){case"number":a[d._id]=Math.max(a[d._id],n[d._id]);break;case"items":oe(a[d._id],...n[d._id])}}r.abilities&&this.merge(a,n,r)}else e[s]=o}return e}hasAbility(e,i){return!!F(e,i)}setAbility(e,i){let t=typeof i=="string"?this.get(i):i;if(!t)throw new Error(`No such ability: ${i}`);return this.merge(e,this.getDefaultAbilities(t)),e}unsetAbility(e,i){let t=typeof i=="string"?this.get(i):i;if(!t)throw new Error(`No such ability: ${i}`);return function s(o){if(ne(e,o.longId),o.abilities)for(let r of o.abilities)s(r)}(t),e}};import{Err as pe}from"@nesvet/n";var U=class extends pe{constructor(e,i){super(`User lacks role${Array.isArray(e)?"s":""}`,"lacksroles",{roles:Array.isArray(e)?e:[e],...i})}name="RolesError"};import{deleteProps as Z,getAll as J,intersection as he,reAdd as me,removeAll as C}from"@nesvet/n";var T=new WeakMap,m=class{constructor(e,i){this.#e=e,this._id=i._id,e.set(this._id,this),this.update(i)}#e;_id;ownInvolveIds;ownAbilities;title="";displayTitle="";_o=0;ownInvolves=[];involves=new Set;abilities={};inheritedAbilities={};update({_id:e,involves:i,abilities:t,title:s,...o}){if(Object.assign(this,o),i&&(this.ownInvolveIds=i),t&&(this.ownAbilities=t),s!==void 0&&(this.title=s,this.displayTitle=s||this._id),i||t){let r=[this.ownInvolveIds.join(","),JSON.stringify(this.ownAbilities)].join(`
2
- `);r!==T.get(this)&&(T.set(this,r),this.#e.users.isInited&&this.#e.update())}}delete(){this.#e.delete(this._id),T.delete(this),this.#e.update()}};var c={_id:/^[\dA-Fa-f]{24}$/,email:/^[^\s@]{1,63}@[^\s@]{1,63}\.[^\s@]{1,63}$/,argon2:/^\$argon2(?:i|d|id)\$v=\d+\$m=\d+,t=\d+,p=\d+(?:\$[\d+/A-Za-z]+){2}$/,sessionId:/^(?:[\dA-Fa-f]{16,32}\$[\dA-Fa-f]{16,32}|[0-9a-f]{24}~[A-Za-z0-9_-]{43})$/,role:/^[\d_a-z-]{1,64}$/,ip:/^(?:\d{1,3}\.){3}\d{1,3}$/};var u={required:["_id","involves","abilities","title","description","meta","createdAt"],properties:{_id:{bsonType:"string",pattern:c.role.source,not:{enum:["root"]}},involves:{bsonType:"array",uniqueItems:!0,items:{bsonType:"string",pattern:c.role.source,not:{enum:["root"]}},additionalItems:!1},abilities:{bsonType:"object"},title:{bsonType:"string",maxLength:256},description:{bsonType:"string",maxLength:10240},meta:{bsonType:"object"},createdAt:{bsonType:"number"}},additionalProperties:!1};var ue=[[{involves:1}]];function X(){throw new Error("Direct usage of roles collection.deleteOne or .deleteMany is forbidden. Use roles.deleteRole instead.")}var v=class extends Map{constructor(e,i={}){super();let{root:t,...s}=i;this.users=e,this.collections=e.collections,this.abilities=e.abilities,this.root=new m(this,{...t,_id:"root",involves:[],abilities:this.abilities.getDefaultAbilities(),title:"Root",description:"Root",meta:{},createdAt:Date.now()}),this.initOptions=s}users;collections;collection;abilities;root;initOptions;async init(){if(!this.users.isInited){let{schema:e,indexes:i,collection:t}=this.initOptions;e&&(e.required&&C(e.required,u.required),e.properties&&Z(e,Object.keys(u.properties)));let s={...u,...e,required:[...u.required,...e?.required??[]],properties:{...u.properties,...e?.properties}};this.collection=Object.assign(await this.collections.ensure("roles",{...t,schema:s}),{deleteOne:X,deleteMany:X}),await this.collection.ensureIndexes([...ue,...i??[]]),await this.#e();for await(let o of this.collection.find())this.abilities.adjust(o.abilities)&&await this.collection.updateOne({_id:o._id},{$set:{abilities:o.abilities}}),this.load(o);this.update(),this.collection.onChange(this.#i),delete this.initOptions}}async#e(){await this.collection.updateMany({meta:{$exists:!1}},{$set:{meta:{}}})}#i=e=>{switch(e.operationType){case"insert":{new m(this,e.fullDocument);break}case"replace":this.get(e.documentKey._id)?.update(e.fullDocument);break;case"update":this.get(e.documentKey._id)?.update(e.updateDescription.updatedFields);break;case"delete":this.get(e.documentKey._id)?.delete()}};load(e){new m(this,e)}resolve(e,i){i=[e,...i];for(let t of e.ownInvolveIds){let s=this.get(t);if(s){for(let o of i)me(o.involves,s),this.abilities.merge(o.inheritedAbilities,s.abilities);s!==e&&this.resolve(s,i)}}}sorted=[];#t(e,i){return i.involves.size-e.involves.size||(e.title&&i.title?e.title>i.title?1:e.title<i.title?-1:0:e.title?-1:i.title||e._id>i._id?1:e._id<i._id?-1:0)}update(){let e=[...this.values()];this.root.ownInvolveIds=[];for(let s of e)s!==this.root&&!e.some(o=>o.ownInvolveIds.includes(s._id))&&this.root.ownInvolveIds.push(s._id),s.involves.clear(),s.abilities=structuredClone(s.ownAbilities),s.inheritedAbilities={};this.root.involves.add(this.root),this.resolve(this.root,[]);for(let s of e)s.ownInvolves=J(this,s.ownInvolveIds,!0).sort(this.#t).reverse();let i=[this.root];for(let s=0;s<i.length;s++){let o=i[s];for(let r of o.ownInvolves){let a=i.indexOf(r);~a&&(i.splice(a,1),s--),i.splice(s+1,0,r)}}let t=0;for(let s of i)this.abilities.merge(s.abilities,s.inheritedAbilities),s._o=t++;this.sorted=i,this.users.isInited&&this.users.update(!0)}async create({_id:e,involves:i,title:t,description:s,...o}){return await this.collection.insertOne({_id:e,involves:i||[],abilities:{},title:t??"",description:s??"",meta:{},...Z(o,["abilities"]),createdAt:Date.now()}),e}async updateRole(e,i){let t=this.get(e);if(!t)return!1;if(i.involves){C(i.involves,[e]);for(let s of i.involves)this.get(s)?.involves.has(t)&&C(i.involves,[s]);i.involves=this.cleanUpIds(i.involves)}return await this.collection.updateOne({_id:e},{$set:i}),!0}deleteRole(e){let i=typeof e=="string"?e:e._id;return this.collection.bulkWrite([{updateMany:{filter:{involves:i},update:{$pullAll:{involves:[i]}}}},{deleteOne:{filter:{_id:i}}}])}cleanUpIds(e){let i=he(this.sorted,J(this,e,!0)),t=[];for(let s of i)i.every(o=>o===s||!o.involves.has(s))&&t.push(s._id);return t}async setAbility(e,i,t){let s=this.get(e);return s?(await this.collection.updateOne({_id:e},{$set:{abilities:t?this.abilities.setAbility(s.ownAbilities,i):this.abilities.unsetAbility(s.ownAbilities,i)}}),!0):!1}async setAbilityParam(e,i,t,s){let o=this.get(e);return o?(await this.collection.updateOne({_id:e},{$set:{abilities:this.abilities.setParam(o.ownAbilities,i,t,s)}}),!0):!1}};import{Err as M}from"@nesvet/n";var j=class extends M{constructor(e){super("Unauthorized","unauthorized",e)}name="UnauthorizedError"},$=class extends M{constructor(e,i,t){switch(arguments.length){case 1:t=e,e=void 0;break;case 2:t=i,i=void 0}super("Insubordination attempt","subordination",{...e&&{type:e},...i&&{ids:Array.isArray(i)?i:[i]},...t})}name="SubordinationError"},E=class extends M{constructor(e){super("Insufficient permissions","permissions",e)}name="PermissionError"};import*as S from"argon2";import je from"eventemitter3";import{_ids as $e,deleteProps as te,removeAll as Ee,StatefulPromise as Me,without as ke}from"@nesvet/n";import{newObjectIdString as qe}from"insite-db";import{_ids as fe,deleteProps as Y,EmptyArray as be,EmptySet as q,removeAll as ye,sort as ge,union as Ae,without as Q}from"@nesvet/n";import{newObjectIdString as Se}from"insite-db";var k=new WeakMap,p=class{constructor(e,i){this.orgs=e,this._id=i._id,e.set(this._id,this),this.update(i)}_id;title="";initials="";displayLabel="";_o=0;orgs;isOrg=!0;ownerOrgs=new Set;ownerUsers=new Set;users=new Set;slaveOrgs=new Set;ownerIds=[];update({_id:e,title:i,owners:t,...s}){if(Object.assign(this,s),i!==void 0&&(this.title=i,this.initials=i?.[0]?.toUpperCase()??"",this.displayLabel=i),t){this.ownerIds=t;let o=this.ownerIds.join(",");o!==k.get(this)&&(k.set(this,o),this.orgs.users.isInited&&this.orgs.update())}}async delete(){this.orgs.delete(this._id),k.delete(this),await this.orgs.replace(this._id),this.orgs.update()}};var f={required:["_id","title","note","owners","meta","createdAt"],properties:{_id:{bsonType:"string",pattern:c._id.source},title:{bsonType:"string",maxLength:512},note:{bsonType:"string",maxLength:131072},owners:{bsonType:"array",uniqueItems:!0,items:{bsonType:"string",pattern:c._id.source},additionalItems:!1},meta:{bsonType:"object"},createdAt:{bsonType:"number"}},additionalProperties:!1};var we=[[{owners:1}]];function V(){throw new Error("Direct usage of orgs collection.deleteOne or .deleteMany is forbidden. Use orgs.deleteOrg instead.")}var O=class extends Map{constructor(e,i={}){super(),this.users=e,this.collections=e.collections,this.preinitOptions=i}users;collections;preinitOptions;collection;null;#e=!1;async preinit(){if(!this.#e){this.#e=!0;let{schema:e,indexes:i,null:t,collection:s}=this.preinitOptions;e&&(e.required&&ye(e.required,f.required),e.properties&&Y(e,Object.keys(f.properties)));let o={...f,...e,required:[...f.required,...e?.required??[]],properties:{...f.properties,...e?.properties}};this.collection=Object.assign(await this.collections.ensure("orgs",{...s,schema:o}),{deleteOne:V,deleteMany:V}),await this.collection.ensureIndexes([...we,...i??[]]),this.null=Object.assign(new p(this,{...t,_id:"",title:"",note:"",owners:[],meta:{},createdAt:Date.now()}),{_id:null,ownerIds:new be,ownerOrgs:new q,ownerUsers:new q,slaveOrgs:new q}),await this.#i();for await(let r of this.collection.find())this.load(r);delete this.preinitOptions}}async#i(){await this.collection.updateMany({meta:{$exists:!1}},{$set:{meta:{}}})}init(){this.users.isInited||(this.update(),this.collection.onChange(this.#t))}#t=e=>{switch(e.operationType){case"insert":{new p(this,e.fullDocument);break}case"replace":this.get(e.documentKey._id)?.update(e.fullDocument);break;case"update":this.get(e.documentKey._id)?.update(e.updateDescription.updatedFields);break;case"delete":this.get(e.documentKey._id)?.delete()}};load(e){new p(this,e)}#o(e,i){i=[e,...i];for(let t of e.ownerOrgs){this.#o(t,i);for(let s of i)t.slaveOrgs.add(s)}}sorted=[];update(){let e=[...this.values()],i=[];for(let t of e){t.ownerOrgs.clear(),t.ownerUsers.clear(),t.slaveOrgs.clear();for(let s of t.ownerIds){let o=this.get(s);if(o)t.ownerOrgs.add(o);else{let r=this.users.get(s);r&&t.ownerUsers.add(r)}}!t.ownerOrgs.size&&t._id&&i.push(t)}for(let t of e)e.some(s=>s.ownerOrgs.has(t))||this.#o(t,[]);i.sort(this.#s);for(let t of e)ge(t.slaveOrgs,this.#s);for(let t=0;t<i.length;t++){let s=i[t];for(let o of[...s.slaveOrgs].reverse())if(o.ownerOrgs.has(s)){let r=i.indexOf(o);~r&&(i.splice(r,1),t--),i.splice(t+1,0,o)}}for(let t=0,{length:s}=i;t<s;)i[t]._o=t++;this.sorted=i,this.users.isInited&&this.users.update()}#s(e,i){return i.slaveOrgs.size-e.slaveOrgs.size||(e.title>i.title?1:e.title<i.title?-1:0)}async create({title:e,note:i,...t}){let s=Se();return await this.collection.insertOne({_id:s,title:e??"",note:i??"",meta:{},...Y(t,["_id"]),createdAt:Date.now()}),s}async updateOrg(e,i,t){let s=this.get(e);return s?(i.owners&&(i.owners=this.users.sortIds(Ae(t?Q(s.ownerIds,t.slaveIds):[],Q(i.owners,[e,...fe(s.slaveOrgs)])))),await this.collection.updateOne({_id:e},{$set:i}),!0):!1}deleteOrg(e){let i=typeof e=="string"?e:e._id;return this.collection.bulkWrite([{updateMany:{filter:{owners:i},update:{$pullAll:{owners:[i]}}}},{deleteOne:{filter:{_id:i}}}])}replaceMap=new Map;replaceHandlers=new Set;async replace(e){let i=this.replaceMap.get(e)??null;i&&this.replaceMap.delete(e);for(let t of this.replaceHandlers)await t(e,i)}};import{randomBytes as ve}from"node:crypto";import{deleteProps as Oe,removeAll as _e}from"@nesvet/n";import{newObjectIdString as Pe}from"insite-db";var b={required:["_id","user","remoteAddress","isOnline","meta","createdAt","prolongedAt","expiresAt"],properties:{_id:{bsonType:"string",pattern:c.sessionId.source},user:{bsonType:"string",pattern:c._id.source},userAgent:{bsonType:"string",maxLength:4096},remoteAddress:{bsonType:"string",pattern:c.ip.source},isOnline:{bsonType:"bool"},meta:{bsonType:"object"},createdAt:{bsonType:"number"},prolongedAt:{bsonType:"number"},expiresAt:{bsonType:"date"}}};var y=class{constructor(e,i){let t=e.users.get(i.user);t?(this.#e=e,this._id=i._id,this.#e.set(this._id,this),this.user=t,this.user.sessions.add(this),this.#e.users.bySessionId.set(this._id,this.user),this.update(i)):e.collection.deleteOne({_id:i._id})}_id;user;isOnline=!1;userAgent;remoteAddress;createdAt;prolongedAt;expiresAt;#e;update({_id:e,user:i,isOnline:t,...s}){t!==void 0&&this.isOnline!==t&&(this.isOnline=t,this.#e.users.isInited&&this.user.isOnline!==this.isOnline&&this.user.updateIsOnlineDebounced()),Object.assign(this,s)}prolong({_id:e,user:i,...t}){let s=Date.now();return t.prolongedAt=s,t.expiresAt=new Date(s+this.#e.collection.expireAfterSeconds*1e3),this.update(t),this.#e.collection.updateOne({_id:this._id},{$set:t})}async online(){if(!this.isOnline){let e={isOnline:!0};this.update(e),await this.#e.collection.updateOne({_id:this._id},{$set:e})}}async offline(){if(this.isOnline){let e={isOnline:!1};this.update(e),await this.#e.collection.updateOne({_id:this._id},{$set:e})}}delete(){this.#e.delete(this._id),this.user.sessions.delete(this),this.#e.users.bySessionId.delete(this._id),this.#e.users.emit("session-delete",this),this.isOnline&&this.user.updateIsOnline()}};var G=3600*24*7,xe=[[{user:1}],[{expiresAt:1},{expireAfterSeconds:G}]],_=class extends Map{constructor(e,i={}){super(),this.users=e,this.collections=e.collections,this.initOptions=i}users;collections;initOptions;collection;async init(){if(!this.users.isInited){let{schema:e,indexes:i,collection:t}=this.initOptions;e&&(e.required&&_e(e.required,b.required),e.properties&&Oe(e,Object.keys(b.properties)));let s={...b,...e,required:[...b.required,...e?.required??[]],properties:{...b.properties,...e?.properties}};this.collection=Object.assign(await this.collections.ensure("sessions",{...t,schema:s}),{expireAfterSeconds:G}),await this.collection.ensureIndexes([...xe,...i??[]]),await this.#e();for await(let o of this.collection.find())this.load(o);this.collection.onChange(this.#i),delete this.initOptions}}async#e(){await this.collection.bulkWrite([{updateMany:{filter:{meta:{$exists:!1}},update:{$set:{meta:{}}}}},{updateMany:{filter:{isOnline:!0},update:{$set:{isOnline:!1}}}}])}#i=e=>{switch(e.operationType){case"insert":this.has(e.documentKey._id)||new y(this,e.fullDocument),this.users.get(e.fullDocument.user)?.trimSessions();break;case"replace":this.get(e.documentKey._id)?.update(e.fullDocument);break;case"update":this.get(e.documentKey._id)?.update(e.updateDescription.updatedFields);break;case"delete":this.get(e.documentKey._id)?.delete()}};uid(){return`${Pe()}~${ve(32).toString("base64url")}`}load(e){new y(this,e)}async create(e,i){let t=Date.now(),s={userAgent:"",remoteAddress:"127.0.0.1",isOnline:!0,...i,_id:this.uid(),user:e._id,meta:{},createdAt:t,prolongedAt:t,expiresAt:new Date(t+G*1e3)},o=new y(this,s);return await this.collection.insertOne(s),o}async destroySession(e){let{deletedCount:i}=await this.collection.deleteOne({_id:e});return!!i}};import{Binary as De}from"insite-db";var ee={required:["_id","type","size","ts","data","meta"],properties:{_id:{bsonType:"string",pattern:c._id.source},type:{bsonType:"string",maxLength:256},size:{bsonType:"number"},ts:{bsonType:"string",maxLength:10},data:{bsonType:"binData"},meta:{bsonType:"object"}},additionalProperties:!1};var P=class{constructor(e,i={}){this.users=e,this.collections=e.collections,this.initOptions=i}TYPES_ACCEPTED=["image/webp"];MAX_SIZE=1024*512;users;collections;collection;initOptions;async init(){if(!this.users.isInited){let{collection:e}=this.initOptions;this.collection=await this.collections.ensure("users.avatars",{...e,schema:ee}),await this.#e()}}async#e(){await this.collection.updateMany({meta:{$exists:!1}},{$set:{meta:{}}})}async save(e,i,t){let s=De.createFromBase64(t.slice(t.indexOf(","))),o=Date.now().toString(36);await Promise.all([this.collection.replaceOne({_id:e},{type:i,size:s.length(),ts:o,data:s,meta:{}},{upsert:!0}),this.users.collection.updateOne({_id:e},{$set:{avatar:o}})])}async deleteAvatar(e){let[{deletedCount:i}]=await Promise.all([this.collection.deleteOne({_id:e}),this.users.collection.updateOne({_id:e},{$set:{avatar:null}})]);return!!i}};var g={required:["_id","email","password","roles","name","org","job","meta","createdAt"],properties:{_id:{bsonType:"string",pattern:c._id.source},email:{bsonType:"string",pattern:c.email.source},password:{bsonType:"string",pattern:c.argon2.source},roles:{bsonType:"array",uniqueItems:!0,items:{bsonType:"string",pattern:c.role.source},additionalItems:!1},name:{bsonType:"object",required:["first","middle","last"],properties:{first:{bsonType:"string",maxLength:512},middle:{bsonType:"string",maxLength:512},last:{bsonType:"string",maxLength:512}},additionalProperties:!1},org:{oneOf:[{bsonType:"string",pattern:c._id.source},{bsonType:"null"}]},job:{bsonType:"string",maxLength:512},avatar:{oneOf:[{bsonType:"string",maxLength:10},{bsonType:"null"}]},meta:{bsonType:"object"},createdAt:{bsonType:"number"}},additionalProperties:!1};import{_ids as ie,debounce as Ie,empty as Re,hasAny as Ue,removeOne as Te}from"@nesvet/n";var N=new WeakMap,L=new WeakMap,Ce=process.env.INSITE_STATIC_URL??"",h=class{constructor(e,i){this.#e=e,this._id=i._id,e.set(this._id,this),this.update(i),e.isInited&&e.emit("user-create",this)}_id;email;name={first:"",middle:"",last:""};initials="";displayLabel="";org;job="";avatar=null;avatarUrl=null;#e;isUser=!0;isRoot;roles=new Set;ownRoles=[];ownRoleIds=[];slaveRoles=new Set;slaveRoleIds=[];abilities={};slaveOrgs=new Set;slaveUsers=new Set;slaves=new Set;slaveIds=[];permissiveIds=[];sessions=new Set;isOnline=!1;update({_id:e,name:i,email:t,roles:s,org:o,avatar:r,...a}){Object.assign(this,a);let n;t&&this.email!==t&&(this.#e.byEmail.delete(this.email),this.email=t,this.#e.byEmail.set(t,this),n=!0);let d,A;i&&(this.name.first!==i.first||this.name.middle!==i.middle||this.name.last!==i.last)&&(A=this.name.last!==i.last,this.name={first:i.first??"",middle:i.middle??"",last:i.last??""},this.initials=((i.first?.[0]??"")+(i.last?.[0]??"")||this.email[0]).toUpperCase(),d=!0),(n||d)&&(this.displayLabel=`${this.name.first} ${this.name.last}`.trim()||this.name.middle||this.email);let z;if(s){this.ownRoleIds=s;let B=this.ownRoleIds.join(",");B!==N.get(this)&&(N.set(this,B),this.#e.isInited&&(this.updateRoles(),z=!0))}let K;o!==void 0&&this.org?._id!==o&&(this.org?.users.delete(this),this.org=o&&this.#e.orgs.get(o)||this.#e.orgs.null,this.org.users.add(this),K=!0),r!==void 0&&this.avatar!==r&&(this.avatar=r,this.avatarUrl=r&&`${Ce}/avatars/${this._id}-${r}.webp`),this.#e.isInited&&(z||K?(this.updatePermissions(),A&&(this.#e.isSortRequired=!0),this.#e.update()):A&&this.#e.sort())}updateRoles(){this.ownRoles=[],this.roles.clear(),this.slaveRoles.clear(),Re(this.abilities);for(let e of this.ownRoleIds){let i=this.#e.roles.get(e);if(i){this.ownRoles.push(i),this.roles.add(i);for(let t of i.involves)this.roles.add(t),this.slaveRoles.add(t);this.slaveRoleIds=ie(this.slaveRoles),this.#e.abilities.merge(this.abilities,i.abilities)}}this.roles.has(this.#e.roles.root)&&(this.isRoot=!0),this.trimSessions()}updatePermissions(){this.slaveOrgs.clear(),this.slaveUsers.clear(),this.slaves.clear();let e=new Set;for(let s of this.#e.orgs.sorted)if((s.ownerUsers.has(this)||this.isRoot)&&!this.slaveOrgs.has(s)){this.slaveOrgs.add(s),this.slaves.add(s),e.add(s._id);for(let o of s.slaveOrgs)this.slaveOrgs.add(o),this.slaves.add(o),e.add(o._id)}for(let s of new Set([this.org,...this.slaveOrgs,this.#e.orgs.null]))for(let o of s.users)o!==this&&(Ue(this.slaveRoles,o.ownRoles)||!o.ownRoles.length)&&(this.slaveUsers.add(o),this.slaves.add(o),e.add(o._id));this.slaveIds=[...e];let i=[];if(this.org._id){i.push(this.org._id);for(let s of this.org.slaveOrgs)this.slaveOrgs.has(s)||i.push(s._id)}this.permissiveIds=[...i,this._id,...e];let t=[this.permissiveIds.join(","),this.ownRoleIds.join(","),JSON.stringify(this.abilities),this.slaveRoleIds.join(",")].join(`
3
- `);t!==L.get(this)&&(L.set(this,t),this.#e.isInited&&this.#e.emit("user-permissions-change",this))}trimSessions(){let e=this.abilities.login?.sessionsLimit??0;if(this.sessions.size>e)return this.#e.sessions.collection.deleteMany({_id:{$in:ie([...this.sessions].sort((i,t)=>i.expiresAt.valueOf()-t.expiresAt.valueOf()).slice(0,this.sessions.size-e))}})}updateIsOnline(){let e=!1;for(let i of this.sessions)if(i.isOnline){e=!0;break}this.isOnline!==e&&(this.isOnline=e,this.#e.emit("user-is-online",this))}updateIsOnlineDebounced=Ie(()=>this.updateIsOnline(),500);async delete(){this.org.users.delete(this),this.#e.delete(this._id),this.#e.byEmail.delete(this.email),Te(this.#e.sorted,this),N.delete(this),L.delete(this),await this.#e.replace(this._id),this.#e.update()}};var Ge=[[{email:1},{unique:!0}],[{org:1}]],W=class l extends Map{constructor(e,i){super();let t=new je;this.#e=t,this._events=t._events,this._eventsCount=t._eventsCount,this.emit=t.emit,this.on=t.on,this.once=t.once,this.addListener=t.addListener,this.off=t.off,this.removeListener=t.removeListener,this.collections=e,this.abilities=new w(i.abilities),this.initOptions=i,this.init()}#e;_events;_eventsCount;emit;on(e,i,t){return this.#e.on(e,i,t),this}once;addListener;off;removeListener;initOptions;collections;abilities;collection;roles;sessions;orgs;avatars;byEmail=new Map;bySessionId=new Map;sorted=[];isSortRequired=!0;#i=!1;async preinit(){if(!this.#i){this.#i=!0;let{indexes:e,schema:i,initialRoot:t,collection:s}=this.initOptions;i&&(i.required&&Ee(i.required,g.required),i.properties&&te(i,Object.keys(g.properties)));let o={...g,...i,required:[...g.required,...i?.required??[]],properties:{...g.properties,...i?.properties}};this.collection=await this.collections.ensure("users",{...s,schema:o}),await this.collection.ensureIndexes([...Ge,...e??[]]),await this.collection.countDocuments({roles:"root"})||await this.create({email:process.env.INSITE_ROOT_EMAIL??"insite@root.email",password:process.env.INSITE_ROOT_PASSWORD??"inSiteRootPassword",name:{first:"Root"},job:"Root",...t,roles:["root"],org:null,meta:{}}),await this.#t();for await(let r of this.collection.find())this.load(r)}}async#t(){await this.collection.updateMany({meta:{$exists:!1}},{$set:{meta:{}}})}isInited=!1;async init(){if(!this.isInited){let{roles:e,orgs:i,sessions:t,avatars:s,collection:{quiet:o}={}}=this.initOptions;this.roles=new v(this,{...e,collection:{quiet:o,...e?.collection}}),this.orgs=new O(this,{...i,collection:{quiet:o,...i?.collection}}),this.sessions=new _(this,{...t,collection:{quiet:o,...t?.collection}}),this.avatars=new P(this,{...s,collection:{quiet:o,...s?.collection}}),await this.roles.init(),await this.orgs.preinit(),await this.preinit(),this.orgs.init(),await this.avatars.init(),this.update(!0),this.collection.onChange(this.#o),await this.sessions.init(),delete this.initOptions,this.isInited=!0,this.#s.resolve(this)}}#o=e=>{switch(e.operationType){case"insert":new h(this,e.fullDocument);break;case"replace":this.get(e.documentKey._id)?.update(e.fullDocument);break;case"update":this.get(e.documentKey._id)?.update(e.updateDescription.updatedFields);break;case"delete":this.get(e.documentKey._id)?.delete()}};load(e){new h(this,e)}sort(){this.isSortRequired=!1,this.sorted=[...this.values()].sort((e,i)=>e.name.last>i.name.last?1:e.name.last<i.name.last?-1:0)}update(e){if(e)for(let i of this.values())i.updateRoles();for(let i of this.values())i.updatePermissions();this.isSortRequired&&this.sort()}#s=new Me;whenReady(){return this.#s}async create({email:e,password:i,roles:t,name:s,org:o,job:r,...a}){if(this.byEmail.has(e))throw new Error("User exists");let n=qe();return await this.collection.insertOne({_id:n,email:e,password:await S.hash(i),roles:this.isInited?this.roles.cleanUpIds(t):t,name:{first:s.first??"",middle:s.middle??"",last:s.last??""},org:o??null,job:r??"",meta:{},...te(a,["_id"]),createdAt:Date.now()}),n}async updateUser(e,i,t){let s=this.get(e);return s?(i.roles&&(i.roles=s.isRoot?["root"]:this.roles.cleanUpIds(t?ke(s.ownRoleIds,t.slaveRoleIds).concat(i.roles):i.roles)),await this.collection.updateOne({_id:e},{$set:i}),!0):!1}async changePassword(e,i){if(!this.has(e))throw new Error("usernotfound");if(!i)throw new Error("emptypasswordisnotallowed");await Promise.all([this.collection.updateOne({_id:e},{$set:{password:await S.hash(i)}}),this.sessions.collection.deleteMany({user:e})])}async login(e,i,t){let s=this.byEmail.get(e);if(!s)throw new Error("usernotfound");if(!await S.verify(s.password,i))throw new Error("incorrectpassword");if(!s.abilities.login)throw new Error("userisnotabletologin");return this.sessions.create(s,t)}logout(e){return e.delete(),this.sessions.collection.deleteOne({_id:e._id})}#r(e,i){return e instanceof h&&i instanceof h?e.name.last&&i.name.last?e.name.last>i.name.last?1:e.name.last<i.name.last?-1:0:!e.name.last&&!i.name.last?e.displayLabel>i.displayLabel?1:e.displayLabel<i.displayLabel?-1:0:e.name.last?-1:1:e instanceof p&&i instanceof p?e.title>i.title?1:e.title<i.title?-1:0:e instanceof p?-1:1}sortIds(e){return $e(e.map(i=>this.get(i)||this.orgs.get(i)).filter(Boolean).sort(this.#r))}replaceMap=new Map;replaceHandlers=new Set;async replace(e){let i=this.replaceMap.get(e)??null;i&&this.replaceMap.delete(e);for(let t of this.replaceHandlers)await t(e,i)}async deleteUser(e){let{deletedCount:i}=await this.collection.deleteOne({_id:e});return!!i}static init(e,i){return new l(e,i).whenReady()}};export{x as AbilityError,E as PermissionError,U as RolesError,$ as SubordinationError,j as UnauthorizedError,W as Users};
1
+ function O(r){if(r instanceof Set){let e=[];for(let t of r)e.push(t._id);return e}return r.map(e=>e._id)}function ce(r,...e){let t=0;for(let i of e)r.includes(i)||(r.push(i),t++);return t}function M(r,e,t){if(r&&e){if(e.includes(".")){let i=e.split("."),s=r;for(let o=0;o<i.length-1;o++){let n=i[o],l=s[n];s=l&&typeof l=="object"?l:s[n]={}}return s[i.at(-1)]=t}return r[e]=t}return null}function de(r,...e){for(let t of e)for(let i in t)Object.hasOwn(t,i)&&M(r,i,t[i]);return r}function S(){}var E=new WeakMap,x=class r extends Promise{constructor(e,t){let i,s;if(super((o,n)=>{i=o,s=n}),E.set(this,{resolve:i,reject:s}),t?.signal)if(t.signal.aborted)this.reject(new DOMException("Aborted","AbortError"));else{let o=()=>this.reject(new DOMException("Aborted","AbortError"));t.signal.addEventListener("abort",o),this.finally(()=>t.signal?.removeEventListener("abort",o))}if(typeof t?.timeout=="number"&&Number.isFinite(t.timeout)){let o=setTimeout(()=>this.reject(new DOMException("Timeout exceeded","TimeoutError")),t.timeout);this.finally(()=>clearTimeout(o))}e?.(this.resolve,this.reject)}isPending=!0;isFulfilled=!1;isRejected=!1;state="pending";result;resolve=e=>{if(this.isPending){this.isPending=!1,this.isFulfilled=!0,this.state="fulfilled",this.result=e;let t=E.get(this);t&&(t.resolve.call(this,e),E.delete(this))}};reject=e=>{if(this.isPending){this.isPending=!1,this.isRejected=!0,this.state="rejected",this.result=e;let t=E.get(this);t&&(t.reject.call(this,e),E.delete(this))}};static resolved(e){return new r(t=>t(e))}static rejected(e){return new r((t,i)=>i(e))}};function K(r,e=0,t={}){let{leading:i=!1,trailing:s=!0}=t,{maxWait:o=1/0}=t,n,l,a,d,g,A,p,w,ae=async()=>{let b=Date.now();b>=a?(n=void 0,a=void 0,clearTimeout(l),l=void 0,typeof p=="function"&&await p(),y.resolve(w),A=i):(clearTimeout(n),n=setTimeout(ae,a-b))},F=Number.isFinite(o)?()=>{p===v&&(p=!1),v(),l=setTimeout(F,o)}:null;async function v(){try{return w=await r.apply(d,g),w}catch(b){throw y.reject(b),b}}i&&typeof i=="boolean"&&(i=v),A=i,s&&typeof s=="boolean"&&(s=v),p=s;let y=Object.assign(function(...b){return g=b,d=this,a=Date.now()+e,p=s,y.promise.isPending||(y.promise=new x((Oe,Pe)=>{y.resolve=Oe,y.reject=Pe,typeof A=="function"&&(A(),A=!1,p===v&&(p=!1)),n||(n=setTimeout(ae,e),F&&(l=setTimeout(F,o)))})),y.promise},{callback:r,promise:x.resolved(void 0),resolve:S,reject:S,run:v,clear:async b=>{clearTimeout(n),n=void 0,clearTimeout(l),l=void 0,y.resolve(b?await v():w)}});return y}K.noop=Object.assign(()=>{},{callback:S,promise:x.resolved(void 0),resolve:S,reject:S,run:S,clear:S});function pe(r,e){if(r&&e){if(e.includes(".")){let t=e.split("."),i=r;for(let o=0;o<t.length-1;o++){let n=t[o],l=i[n];if(l&&typeof l=="object")i=l;else return!1}let s=t.at(-1);return s in i&&delete i[s]}return e in r&&delete r[e]}return!1}function u(r,e){if(r){for(let t of e)delete r[t];return r}return null}function U(r){for(let e in r)delete r[e];return r}var C=class extends Array{constructor(){super(),Object.freeze(this)}push(){return 0}unshift(){return 0}splice(){return[]}};var _=class extends Set{constructor(){super()}add(){return this}};var f=class extends Error{constructor(e,t=null,i){typeof e=="object"?(i=e,e=i.message,delete i.message,t=null):t&&typeof t=="object"&&(i=t,t=null),super(e),this.tag=t,i&&Object.assign(this,i)}name="Err-or";tag};function J(r,e,t=!1){let i=[];if(t)for(let s of e){let o=r.get(s);o!==void 0&&i.push(o)}else for(let s of e)i.push(r.get(s));return i}function N(r,e){if(e){if(e.includes(".")){let t=r;for(let i of e.split("."))if(t=t?.[i],t===void 0)break;return t}return r[e]}return r}function ue(r,e){for(let t of e)if(r.has(t))return!0;return!1}function fe(r,e,t,i,s=!0){return Array.isArray(r)&&(r=r.length),typeof i!="string"&&(s=i??!0,i=t),(s?`${r}\xA0`:"")+fe.raw(r,e,t,i)}fe.raw=(r,e,t,i=t)=>{r=Math.abs(r);let s=r%10,o=r%100;return s===1&&o!==11?e:s>=2&&s<=4&&!(o>=12&&o<=15)?t:i};function q(...r){let e=[];if(r.length){let[t,...i]=r;e:for(let s of t){for(let o of i)if(o instanceof Set?!o.has(s):!o.includes(s))continue e;e.push(s)}}return e}function he(r,e){let t={};for(let i of e)i in r&&(t[i]=r[i]);return t}function me(r,e){return r.delete(e),r.add(e),r}function h(r,e){let t,i=0;for(let s of e)for(;(t=r.indexOf(s))>-1;)r.splice(t,1),i++;return i}function ye(r,e){let t=r.indexOf(e);return t>-1?(r.splice(t,1),!0):!1}function be(r,e){for(let t of[...r].sort(e))r.delete(t),r.add(t);return r}function ge(...r){return[...new Set(r.flat())]}function k(r,e){return r.filter(t=>!e.includes(t))}var H=class extends f{constructor(e,t){typeof e=="object"&&(t=e,e=void 0),super("User lacks ability","lacksability",{...e&&{ability:e},...t})}name="AbilityError"};function V(r){return typeof r=="object"}function Z(r){return typeof r=="number"}function X(r){return Array.isArray(r)}var Ae=new Map,W=class extends Map{constructor(e){super();for(let t of e)delete t.top,this.#e.push(t);(function t(i,s,o){for(let n of i){if(Ae.set(n,s),n.level=o,!s||n.top){if(n.longId=n._id,this.has(n._id))throw new Error(`Top-level ability duplicate: ${n._id}`);this.set(n._id,n)}else n.longId=s?`${s.longId}.${n._id}`:n._id;n.abilities&&t.call(this,n.abilities,n,o+1)}}).call(this,e,null,0)}#e=[];get(e,t){let i=e.split("."),s=t??super.get(i.shift());if(s&&i.length){for(let o of i)if(s=s?.abilities?.find(({_id:n,top:l})=>!l&&n===o),!s)break}return s}getSchema=this.get;getParamSchema(e,t){return this.get(e)?.params?.find(({_id:i})=>i===t)}getDefaultParam(e,t,i){(t===void 0||typeof t=="boolean")&&(i=t);let s=typeof e=="string"?this.getParamSchema(e,t):e;if(s)switch(s.type){case"number":return i?s.max??1/0:s.min??0;case"items":return i?s.items.map(({_id:o})=>o):[]}}getDefaultAbility(e,t=!e){if(typeof e=="string"&&(e=this.get(e)),e){if(e.abilities||e.params){let i={};if(e.params)for(let s of e.params)i[s._id]=this.getDefaultParam(s,t);if(t&&e.abilities)for(let s of e.abilities)s.top||(i[s._id]=this.getDefaultAbility(s,t));return i}return!0}}getDefaultAbilities(e,t=!e){let i=(e?(Array.isArray(e)?e:[e]).map(o=>typeof o=="string"?this.get(o):o).filter(Boolean):[...this.values()]).sort((o,n)=>o.level-n.level),s=new Map;for(let o of i)(function n(l){let a=Ae.get(l);a&&(n(a),s.has(a)||s.set(a,!1))})(o),t?function n(l){if(s.has(l)||s.set(l,!0),l.abilities)for(let a of l.abilities)a.top&&n(a)}(o):s.has(o)||s.set(o,!1);return de({},Object.fromEntries([...s].map(([o,n])=>[o.longId,this.getDefaultAbility(o,n)])))}getSchemeFor(e){return e=this.adjust(structuredClone(e)),function t(i,s){for(let o=0;o<i.length;o++){let n=i[o],l=n.top?e[n._id]:s[n._id];if(l){if(n.params)for(let a of n.params){let d=l[a._id];switch(a.type){case"number":a.max=d;break;case"items":a.items=a.items.filter(({_id:g})=>d.includes(g))}}n.abilities&&(t(n.abilities,l),n.abilities.length||delete n.abilities)}else i.splice(o--,1)}return i}(structuredClone(this.#e),e)}getParam(e,t,i){if(this.getParamSchema(t,i)){let s=N(e,`${t}.${i}`);return this.isParamFits(t,i,s)?s:this.getDefaultParam(t,i)}}setParam(e,t,i,s){let o=this.getParamSchema(t,i);if(!o)throw new Error(`No such ability param: ${t}.${i}`);return M(e,`${t}.${i}`,this.adjustParam(o,s)),e}isParamFits(e,t,i,s){if(i!==void 0){let o=this.getParamSchema(e,t);if(o)switch(o.type){case"number":return Z(i)&&(o.min===void 0||i>=o.min)&&(s===void 0?o.max===void 0||i<=o.max:i<=s);case"items":return X(i)&&i.length===new Set(i).size&&(s===void 0?i.every(n=>o.items.find(({_id:l})=>l===n)):i.every(n=>s.includes(n)))}}return!1}adjustParam(e,t){switch(e.type){case"number":return Z(t)?Math.max(Math.min(t,e.max??1/0),e.min??0):e.min??0;default:return X(t)?q(e.items.map(i=>i._id),t):[]}}adjust(e,t){let i={};for(let[s,o]of Object.entries(e)){let n=this.get(s,t);if(n)if(n.params||n.abilities){let l={};if(n.params)if(V(o))for(let a of n.params)l[a._id]=this.adjustParam(a,o[a._id]);else for(let a of n.params)l[a._id]=this.getDefaultParam(a);n.abilities&&V(o)&&Object.assign(l,this.adjust(he(o,n.abilities.filter(a=>!a.top).map(a=>a._id)),n)),i[s]=l}else i[s]=!0}return Object.assign(U(e),i)}merge(e,t,i){i||(this.adjust(e),t=this.adjust(structuredClone(t)));for(let[s,o]of Object.entries(t)){let n=this.get(s,i);if(n&&n.isInheritable!==!1)if(s in e&&(n.params||n.abilities)){let l=e[s],a=o;if(n.params){for(let d of n.params)if(d.isInheritable!==!1)switch(d.type){case"number":l[d._id]=Math.max(l[d._id],a[d._id]);break;case"items":ce(l[d._id],...a[d._id])}}n.abilities&&this.merge(l,a,n)}else e[s]=o}return e}hasAbility(e,t){return!!N(e,t)}setAbility(e,t){let i=typeof t=="string"?this.get(t):t;if(!i)throw new Error(`No such ability: ${t}`);return this.merge(e,this.getDefaultAbilities(i)),e}unsetAbility(e,t){let i=typeof t=="string"?this.get(t):t;if(!i)throw new Error(`No such ability: ${t}`);return function s(o){if(pe(e,o.longId),o.abilities)for(let n of o.abilities)s(n)}(i),e}};var Y=class extends f{constructor(e,t){super(`User lacks role${Array.isArray(e)?"s":""}`,"lacksroles",{roles:Array.isArray(e)?e:[e],...t})}name="RolesError"};var Q=new WeakMap,D=class{constructor(e,t){this.#e=e,this._id=t._id,e.set(this._id,this),this.update(t)}#e;_id;ownInvolveIds;ownAbilities;title="";displayTitle="";_o=0;ownInvolves=[];involves=new Set;abilities={};inheritedAbilities={};update({_id:e,involves:t,abilities:i,title:s,...o}){if(Object.assign(this,o),t&&(this.ownInvolveIds=t),i&&(this.ownAbilities=i),s!==void 0&&(this.title=s,this.displayTitle=s||this._id),t||i){let n=[this.ownInvolveIds.join(","),JSON.stringify(this.ownAbilities)].join(`
2
+ `);n!==Q.get(this)&&(Q.set(this,n),this.#e.users.isInited&&this.#e.update())}}delete(){this.#e.delete(this._id),Q.delete(this),this.#e.update()}};var c={_id:/^[\dA-Fa-f]{24}$/,email:/^[^\s@]{1,63}@[^\s@]{1,63}\.[^\s@]{1,63}$/,argon2:/^\$argon2(?:i|d|id)\$v=\d+\$m=\d+,t=\d+,p=\d+(?:\$[\d+/A-Za-z]+){2}$/,sessionId:/^(?:[\dA-Fa-f]{16,32}\$[\dA-Fa-f]{16,32}|[0-9a-f]{24}~[A-Za-z0-9_-]{43})$/,role:/^[\d_a-z-]{1,64}$/,ip:/^(?:\d{1,3}\.){3}\d{1,3}$/};var I={required:["_id","involves","abilities","title","description","meta","createdAt"],properties:{_id:{bsonType:"string",pattern:c.role.source,not:{enum:["root"]}},involves:{bsonType:"array",uniqueItems:!0,items:{bsonType:"string",pattern:c.role.source,not:{enum:["root"]}},additionalItems:!1},abilities:{bsonType:"object"},title:{bsonType:"string",maxLength:256},description:{bsonType:"string",maxLength:10240},meta:{bsonType:"object"},createdAt:{bsonType:"number"}},additionalProperties:!1};var _e=[[{involves:1}]];function Se(){throw new Error("Direct usage of roles collection.deleteOne or .deleteMany is forbidden. Use roles.deleteRole instead.")}var G=class extends Map{constructor(e,t={}){super();let{root:i,...s}=t;this.users=e,this.collections=e.collections,this.abilities=e.abilities,this.root=new D(this,{...i,_id:"root",involves:[],abilities:this.abilities.getDefaultAbilities(),title:"Root",description:"Root",meta:{},createdAt:Date.now()}),this.initOptions=s}users;collections;collection;abilities;root;initOptions;async init(){if(!this.users.isInited){let{schema:e,indexes:t,collection:i}=this.initOptions;e&&(e.required&&h(e.required,I.required),e.properties&&u(e,Object.keys(I.properties)));let s={...I,...e,required:[...I.required,...e?.required??[]],properties:{...I.properties,...e?.properties}};this.collection=Object.assign(await this.collections.ensure("roles",{...i,schema:s}),{deleteOne:Se,deleteMany:Se}),await this.collection.ensureIndexes([..._e,...t??[]]),await this.#e();for await(let o of this.collection.find())this.abilities.adjust(o.abilities)&&await this.collection.updateOne({_id:o._id},{$set:{abilities:o.abilities}}),this.load(o);this.update(),this.collection.onChange(this.#t),delete this.initOptions}}async#e(){await this.collection.updateMany({meta:{$exists:!1}},{$set:{meta:{}}})}#t=e=>{switch(e.operationType){case"insert":{new D(this,e.fullDocument);break}case"replace":this.get(e.documentKey._id)?.update(e.fullDocument);break;case"update":this.get(e.documentKey._id)?.update(e.updateDescription.updatedFields);break;case"delete":this.get(e.documentKey._id)?.delete()}};load(e){new D(this,e)}resolve(e,t){t=[e,...t];for(let i of e.ownInvolveIds){let s=this.get(i);if(s){for(let o of t)me(o.involves,s),this.abilities.merge(o.inheritedAbilities,s.abilities);s!==e&&this.resolve(s,t)}}}sorted=[];#i(e,t){return t.involves.size-e.involves.size||(e.title&&t.title?e.title>t.title?1:e.title<t.title?-1:0:e.title?-1:t.title||e._id>t._id?1:e._id<t._id?-1:0)}update(){let e=[...this.values()];this.root.ownInvolveIds=[];for(let s of e)s!==this.root&&!e.some(o=>o.ownInvolveIds.includes(s._id))&&this.root.ownInvolveIds.push(s._id),s.involves.clear(),s.abilities=structuredClone(s.ownAbilities),s.inheritedAbilities={};this.root.involves.add(this.root),this.resolve(this.root,[]);for(let s of e)s.ownInvolves=J(this,s.ownInvolveIds,!0).sort(this.#i).reverse();let t=[this.root];for(let s=0;s<t.length;s++){let o=t[s];for(let n of o.ownInvolves){let l=t.indexOf(n);~l&&(t.splice(l,1),s--),t.splice(s+1,0,n)}}let i=0;for(let s of t)this.abilities.merge(s.abilities,s.inheritedAbilities),s._o=i++;this.sorted=t,this.users.isInited&&this.users.update(!0)}async create({_id:e,involves:t,title:i,description:s,...o}){return await this.collection.insertOne({_id:e,involves:t||[],abilities:{},title:i??"",description:s??"",meta:{},...u(o,["abilities"]),createdAt:Date.now()}),e}async updateRole(e,t){let i=this.get(e);if(!i)return!1;if(t.involves){h(t.involves,[e]);for(let s of t.involves)this.get(s)?.involves.has(i)&&h(t.involves,[s]);t.involves=this.cleanUpIds(t.involves)}return await this.collection.updateOne({_id:e},{$set:t}),!0}deleteRole(e){let t=typeof e=="string"?e:e._id;return this.collection.bulkWrite([{updateMany:{filter:{involves:t},update:{$pullAll:{involves:[t]}}}},{deleteOne:{filter:{_id:t}}}])}cleanUpIds(e){let t=q(this.sorted,J(this,e,!0)),i=[];for(let s of t)t.every(o=>o===s||!o.involves.has(s))&&i.push(s._id);return i}async setAbility(e,t,i){let s=this.get(e);return s?(await this.collection.updateOne({_id:e},{$set:{abilities:i?this.abilities.setAbility(s.ownAbilities,t):this.abilities.unsetAbility(s.ownAbilities,t)}}),!0):!1}async setAbilityParam(e,t,i,s){let o=this.get(e);return o?(await this.collection.updateOne({_id:e},{$set:{abilities:this.abilities.setParam(o.ownAbilities,t,i,s)}}),!0):!1}};var ee=class extends f{constructor(e){super("Unauthorized","unauthorized",e)}name="UnauthorizedError"},te=class extends f{constructor(e,t,i){switch(arguments.length){case 1:i=e,e=void 0;break;case 2:i=t,t=void 0}super("Insubordination attempt","subordination",{...e&&{type:e},...t&&{ids:Array.isArray(t)?t:[t]},...i})}name="SubordinationError"},ie=class extends f{constructor(e){super("Insufficient permissions","permissions",e)}name="PermissionError"};import{hash as ve,verify as ke}from"@node-rs/argon2";import Me from"eventemitter3";import{newObjectIdString as Ue}from"insite-db";import{newObjectIdString as De}from"insite-db";var se=new WeakMap,m=class{constructor(e,t){this.orgs=e,this._id=t._id,e.set(this._id,this),this.update(t)}_id;title="";initials="";displayLabel="";_o=0;orgs;isOrg=!0;ownerOrgs=new Set;ownerUsers=new Set;users=new Set;slaveOrgs=new Set;ownerIds=[];update({_id:e,title:t,owners:i,...s}){if(Object.assign(this,s),t!==void 0&&(this.title=t,this.initials=t?.[0]?.toUpperCase()??"",this.displayLabel=t),i){this.ownerIds=i;let o=this.ownerIds.join(",");o!==se.get(this)&&(se.set(this,o),this.orgs.users.isInited&&this.orgs.update())}}async delete(){this.orgs.delete(this._id),se.delete(this),await this.orgs.replace(this._id),this.orgs.update()}};var j={required:["_id","title","note","owners","meta","createdAt"],properties:{_id:{bsonType:"string",pattern:c._id.source},title:{bsonType:"string",maxLength:512},note:{bsonType:"string",maxLength:131072},owners:{bsonType:"array",uniqueItems:!0,items:{bsonType:"string",pattern:c._id.source},additionalItems:!1},meta:{bsonType:"object"},createdAt:{bsonType:"number"}},additionalProperties:!1};var Ie=[[{owners:1}]];function xe(){throw new Error("Direct usage of orgs collection.deleteOne or .deleteMany is forbidden. Use orgs.deleteOrg instead.")}var L=class extends Map{constructor(e,t={}){super(),this.users=e,this.collections=e.collections,this.preinitOptions=t}users;collections;preinitOptions;collection;null;#e=!1;async preinit(){if(!this.#e){this.#e=!0;let{schema:e,indexes:t,null:i,collection:s}=this.preinitOptions;e&&(e.required&&h(e.required,j.required),e.properties&&u(e,Object.keys(j.properties)));let o={...j,...e,required:[...j.required,...e?.required??[]],properties:{...j.properties,...e?.properties}};this.collection=Object.assign(await this.collections.ensure("orgs",{...s,schema:o}),{deleteOne:xe,deleteMany:xe}),await this.collection.ensureIndexes([...Ie,...t??[]]),this.null=Object.assign(new m(this,{...i,_id:"",title:"",note:"",owners:[],meta:{},createdAt:Date.now()}),{_id:null,ownerIds:new C,ownerOrgs:new _,ownerUsers:new _,slaveOrgs:new _}),await this.#t();for await(let n of this.collection.find())this.load(n);delete this.preinitOptions}}async#t(){await this.collection.updateMany({meta:{$exists:!1}},{$set:{meta:{}}})}init(){this.users.isInited||(this.update(),this.collection.onChange(this.#i))}#i=e=>{switch(e.operationType){case"insert":{new m(this,e.fullDocument);break}case"replace":this.get(e.documentKey._id)?.update(e.fullDocument);break;case"update":this.get(e.documentKey._id)?.update(e.updateDescription.updatedFields);break;case"delete":this.get(e.documentKey._id)?.delete()}};load(e){new m(this,e)}#o(e,t){t=[e,...t];for(let i of e.ownerOrgs){this.#o(i,t);for(let s of t)i.slaveOrgs.add(s)}}sorted=[];update(){let e=[...this.values()],t=[];for(let i of e){i.ownerOrgs.clear(),i.ownerUsers.clear(),i.slaveOrgs.clear();for(let s of i.ownerIds){let o=this.get(s);if(o)i.ownerOrgs.add(o);else{let n=this.users.get(s);n&&i.ownerUsers.add(n)}}!i.ownerOrgs.size&&i._id&&t.push(i)}for(let i of e)e.some(s=>s.ownerOrgs.has(i))||this.#o(i,[]);t.sort(this.#s);for(let i of e)be(i.slaveOrgs,this.#s);for(let i=0;i<t.length;i++){let s=t[i];for(let o of[...s.slaveOrgs].reverse())if(o.ownerOrgs.has(s)){let n=t.indexOf(o);~n&&(t.splice(n,1),i--),t.splice(i+1,0,o)}}for(let i=0,{length:s}=t;i<s;)t[i]._o=i++;this.sorted=t,this.users.isInited&&this.users.update()}#s(e,t){return t.slaveOrgs.size-e.slaveOrgs.size||(e.title>t.title?1:e.title<t.title?-1:0)}async create({title:e,note:t,...i}){let s=De();return await this.collection.insertOne({_id:s,title:e??"",note:t??"",meta:{},...u(i,["_id"]),createdAt:Date.now()}),s}async updateOrg(e,t,i){let s=this.get(e);return s?(t.owners&&(t.owners=this.users.sortIds(ge(i?k(s.ownerIds,i.slaveIds):[],k(t.owners,[e,...O(s.slaveOrgs)])))),await this.collection.updateOne({_id:e},{$set:t}),!0):!1}deleteOrg(e){let t=typeof e=="string"?e:e._id;return this.collection.bulkWrite([{updateMany:{filter:{owners:t},update:{$pullAll:{owners:[t]}}}},{deleteOne:{filter:{_id:t}}}])}replaceMap=new Map;replaceHandlers=new Set;async replace(e){let t=this.replaceMap.get(e)??null;t&&this.replaceMap.delete(e);for(let i of this.replaceHandlers)await i(e,t)}};import{randomBytes as je}from"node:crypto";import{newObjectIdString as Re}from"insite-db";var R={required:["_id","user","remoteAddress","isOnline","meta","createdAt","prolongedAt","expiresAt"],properties:{_id:{bsonType:"string",pattern:c.sessionId.source},user:{bsonType:"string",pattern:c._id.source},userAgent:{bsonType:"string",maxLength:4096},remoteAddress:{bsonType:"string",pattern:c.ip.source},isOnline:{bsonType:"bool"},meta:{bsonType:"object"},createdAt:{bsonType:"number"},prolongedAt:{bsonType:"number"},expiresAt:{bsonType:"date"}}};var $=class{constructor(e,t){let i=e.users.get(t.user);i?(this.#e=e,this._id=t._id,this.#e.set(this._id,this),this.user=i,this.user.sessions.add(this),this.#e.users.bySessionId.set(this._id,this.user),this.update(t)):e.collection.deleteOne({_id:t._id})}_id;user;isOnline=!1;userAgent;remoteAddress;createdAt;prolongedAt;expiresAt;#e;update({_id:e,user:t,isOnline:i,...s}){i!==void 0&&this.isOnline!==i&&(this.isOnline=i,this.#e.users.isInited&&this.user.isOnline!==this.isOnline&&this.user.updateIsOnlineDebounced()),Object.assign(this,s)}prolong({_id:e,user:t,...i}){let s=Date.now();return i.prolongedAt=s,i.expiresAt=new Date(s+this.#e.collection.expireAfterSeconds*1e3),this.update(i),this.#e.collection.updateOne({_id:this._id},{$set:i})}async online(){if(!this.isOnline){let e={isOnline:!0};this.update(e),await this.#e.collection.updateOne({_id:this._id},{$set:e})}}async offline(){if(this.isOnline){let e={isOnline:!1};this.update(e),await this.#e.collection.updateOne({_id:this._id},{$set:e})}}delete(){this.#e.delete(this._id),this.user.sessions.delete(this),this.#e.users.bySessionId.delete(this._id),this.#e.users.emit("session-delete",this),this.isOnline&&this.user.updateIsOnline()}};var oe=3600*24*7,$e=[[{user:1}],[{expiresAt:1},{expireAfterSeconds:oe}]],B=class extends Map{constructor(e,t={}){super(),this.users=e,this.collections=e.collections,this.initOptions=t}users;collections;initOptions;collection;async init(){if(!this.users.isInited){let{schema:e,indexes:t,collection:i}=this.initOptions;e&&(e.required&&h(e.required,R.required),e.properties&&u(e,Object.keys(R.properties)));let s={...R,...e,required:[...R.required,...e?.required??[]],properties:{...R.properties,...e?.properties}};this.collection=Object.assign(await this.collections.ensure("sessions",{...i,schema:s}),{expireAfterSeconds:oe}),await this.collection.ensureIndexes([...$e,...t??[]]),await this.#e();for await(let o of this.collection.find())this.load(o);this.collection.onChange(this.#t),delete this.initOptions}}async#e(){await this.collection.bulkWrite([{updateMany:{filter:{meta:{$exists:!1}},update:{$set:{meta:{}}}}},{updateMany:{filter:{isOnline:!0},update:{$set:{isOnline:!1}}}}])}#t=e=>{switch(e.operationType){case"insert":this.has(e.documentKey._id)||new $(this,e.fullDocument),this.users.get(e.fullDocument.user)?.trimSessions();break;case"replace":this.get(e.documentKey._id)?.update(e.fullDocument);break;case"update":this.get(e.documentKey._id)?.update(e.updateDescription.updatedFields);break;case"delete":this.get(e.documentKey._id)?.delete()}};uid(){return`${Re()}~${je(32).toString("base64url")}`}load(e){new $(this,e)}async create(e,t){let i=Date.now(),s={userAgent:"",remoteAddress:"127.0.0.1",isOnline:!0,...t,_id:this.uid(),user:e._id,meta:{},createdAt:i,prolongedAt:i,expiresAt:new Date(i+oe*1e3)},o=new $(this,s);return await this.collection.insertOne(s),o}async destroySession(e){let{deletedCount:t}=await this.collection.deleteOne({_id:e});return!!t}};import{Binary as Te}from"insite-db";var we={required:["_id","type","size","ts","data","meta"],properties:{_id:{bsonType:"string",pattern:c._id.source},type:{bsonType:"string",maxLength:256},size:{bsonType:"number"},ts:{bsonType:"string",maxLength:10},data:{bsonType:"binData"},meta:{bsonType:"object"}},additionalProperties:!1};var z=class{constructor(e,t={}){this.users=e,this.collections=e.collections,this.initOptions=t}TYPES_ACCEPTED=["image/webp"];MAX_SIZE=1024*512;users;collections;collection;initOptions;async init(){if(!this.users.isInited){let{collection:e}=this.initOptions;this.collection=await this.collections.ensure("users.avatars",{...e,schema:we}),await this.#e()}}async#e(){await this.collection.updateMany({meta:{$exists:!1}},{$set:{meta:{}}})}async save(e,t,i){let s=Te.createFromBase64(i.slice(i.indexOf(","))),o=Date.now().toString(36);await Promise.all([this.collection.replaceOne({_id:e},{type:t,size:s.length(),ts:o,data:s,meta:{}},{upsert:!0}),this.users.collection.updateOne({_id:e},{$set:{avatar:o}})])}async deleteAvatar(e){let[{deletedCount:t}]=await Promise.all([this.collection.deleteOne({_id:e}),this.users.collection.updateOne({_id:e},{$set:{avatar:null}})]);return!!t}};var T={required:["_id","email","password","roles","name","org","job","meta","createdAt"],properties:{_id:{bsonType:"string",pattern:c._id.source},email:{bsonType:"string",pattern:c.email.source},password:{bsonType:"string",pattern:c.argon2.source},roles:{bsonType:"array",uniqueItems:!0,items:{bsonType:"string",pattern:c.role.source},additionalItems:!1},name:{bsonType:"object",required:["first","middle","last"],properties:{first:{bsonType:"string",maxLength:512},middle:{bsonType:"string",maxLength:512},last:{bsonType:"string",maxLength:512}},additionalProperties:!1},org:{oneOf:[{bsonType:"string",pattern:c._id.source},{bsonType:"null"}]},job:{bsonType:"string",maxLength:512},avatar:{oneOf:[{bsonType:"string",maxLength:10},{bsonType:"null"}]},meta:{bsonType:"object"},createdAt:{bsonType:"number"}},additionalProperties:!1};var re=new WeakMap,ne=new WeakMap,Ee=process.env.INSITE_STATIC_URL??"",P=class{constructor(e,t){this.#e=e,this._id=t._id,e.set(this._id,this),this.update(t),e.isInited&&e.emit("user-create",this)}_id;email;name={first:"",middle:"",last:""};initials="";displayLabel="";org;job="";avatar=null;avatarUrl=null;#e;isUser=!0;isRoot;roles=new Set;ownRoles=[];ownRoleIds=[];slaveRoles=new Set;slaveRoleIds=[];abilities={};slaveOrgs=new Set;slaveUsers=new Set;slaves=new Set;slaveIds=[];permissiveIds=[];sessions=new Set;isOnline=!1;update({_id:e,name:t,email:i,roles:s,org:o,avatar:n,...l}){Object.assign(this,l);let a;i&&this.email!==i&&(this.#e.byEmail.delete(this.email),this.email=i,this.#e.byEmail.set(i,this),a=!0);let d,g;t&&(this.name.first!==t.first||this.name.middle!==t.middle||this.name.last!==t.last)&&(g=this.name.last!==t.last,this.name={first:t.first??"",middle:t.middle??"",last:t.last??""},this.initials=((t.first?.[0]??"")+(t.last?.[0]??"")||this.email[0]).toUpperCase(),d=!0),(a||d)&&(this.displayLabel=`${this.name.first} ${this.name.last}`.trim()||this.name.middle||this.email);let A;if(s){this.ownRoleIds=s;let w=this.ownRoleIds.join(",");w!==re.get(this)&&(re.set(this,w),this.#e.isInited&&(this.updateRoles(),A=!0))}let p;o!==void 0&&this.org?._id!==o&&(this.org?.users.delete(this),this.org=o&&this.#e.orgs.get(o)||this.#e.orgs.null,this.org.users.add(this),p=!0),n!==void 0&&this.avatar!==n&&(this.avatar=n,this.avatarUrl=n&&`${Ee}/avatars/${this._id}-${n}.webp`),this.#e.isInited&&(A||p?(this.updatePermissions(),g&&(this.#e.isSortRequired=!0),this.#e.update()):g&&this.#e.sort())}updateRoles(){this.ownRoles=[],this.roles.clear(),this.slaveRoles.clear(),U(this.abilities);for(let e of this.ownRoleIds){let t=this.#e.roles.get(e);if(t){this.ownRoles.push(t),this.roles.add(t);for(let i of t.involves)this.roles.add(i),this.slaveRoles.add(i);this.slaveRoleIds=O(this.slaveRoles),this.#e.abilities.merge(this.abilities,t.abilities)}}this.roles.has(this.#e.roles.root)&&(this.isRoot=!0),this.trimSessions()}updatePermissions(){this.slaveOrgs.clear(),this.slaveUsers.clear(),this.slaves.clear();let e=new Set;for(let s of this.#e.orgs.sorted)if((s.ownerUsers.has(this)||this.isRoot)&&!this.slaveOrgs.has(s)){this.slaveOrgs.add(s),this.slaves.add(s),e.add(s._id);for(let o of s.slaveOrgs)this.slaveOrgs.add(o),this.slaves.add(o),e.add(o._id)}for(let s of new Set([this.org,...this.slaveOrgs,this.#e.orgs.null]))for(let o of s.users)o!==this&&(ue(this.slaveRoles,o.ownRoles)||!o.ownRoles.length)&&(this.slaveUsers.add(o),this.slaves.add(o),e.add(o._id));this.slaveIds=[...e];let t=[];if(this.org._id){t.push(this.org._id);for(let s of this.org.slaveOrgs)this.slaveOrgs.has(s)||t.push(s._id)}this.permissiveIds=[...t,this._id,...e];let i=[this.permissiveIds.join(","),this.ownRoleIds.join(","),JSON.stringify(this.abilities),this.slaveRoleIds.join(",")].join(`
3
+ `);i!==ne.get(this)&&(ne.set(this,i),this.#e.isInited&&this.#e.emit("user-permissions-change",this))}trimSessions(){let e=this.abilities.login?.sessionsLimit??0;if(this.sessions.size>e)return this.#e.sessions.collection.deleteMany({_id:{$in:O([...this.sessions].sort((t,i)=>t.expiresAt.valueOf()-i.expiresAt.valueOf()).slice(0,this.sessions.size-e))}})}updateIsOnline(){let e=!1;for(let t of this.sessions)if(t.isOnline){e=!0;break}this.isOnline!==e&&(this.isOnline=e,this.#e.emit("user-is-online",this))}updateIsOnlineDebounced=K(()=>this.updateIsOnline(),500);async delete(){this.org.users.delete(this),this.#e.delete(this._id),this.#e.byEmail.delete(this.email),ye(this.#e.sorted,this),re.delete(this),ne.delete(this),await this.#e.replace(this._id),this.#e.update()}};var Ce=[[{email:1},{unique:!0}],[{org:1}]],le=class r extends Map{constructor(e,t){super();let i=new Me;this.#e=i,this._events=i._events,this._eventsCount=i._eventsCount,this.emit=i.emit,this.on=i.on,this.once=i.once,this.addListener=i.addListener,this.off=i.off,this.removeListener=i.removeListener,this.collections=e,this.abilities=new W(t.abilities),this.initOptions=t,this.init()}#e;_events;_eventsCount;emit;on(e,t,i){return this.#e.on(e,t,i),this}once;addListener;off;removeListener;initOptions;collections;abilities;collection;roles;sessions;orgs;avatars;byEmail=new Map;bySessionId=new Map;sorted=[];isSortRequired=!0;#t=!1;async preinit(){if(!this.#t){this.#t=!0;let{indexes:e,schema:t,initialRoot:i,collection:s}=this.initOptions;t&&(t.required&&h(t.required,T.required),t.properties&&u(t,Object.keys(T.properties)));let o={...T,...t,required:[...T.required,...t?.required??[]],properties:{...T.properties,...t?.properties}};this.collection=await this.collections.ensure("users",{...s,schema:o}),await this.collection.ensureIndexes([...Ce,...e??[]]),await this.collection.countDocuments({roles:"root"})||await this.create({email:process.env.INSITE_ROOT_EMAIL??"insite@root.email",password:process.env.INSITE_ROOT_PASSWORD??"inSiteRootPassword",name:{first:"Root"},job:"Root",...i,roles:["root"],org:null,meta:{}}),await this.#i();for await(let n of this.collection.find())this.load(n)}}async#i(){await this.collection.updateMany({meta:{$exists:!1}},{$set:{meta:{}}})}isInited=!1;async init(){if(!this.isInited){let{roles:e,orgs:t,sessions:i,avatars:s,collection:{quiet:o}={}}=this.initOptions;this.roles=new G(this,{...e,collection:{quiet:o,...e?.collection}}),this.orgs=new L(this,{...t,collection:{quiet:o,...t?.collection}}),this.sessions=new B(this,{...i,collection:{quiet:o,...i?.collection}}),this.avatars=new z(this,{...s,collection:{quiet:o,...s?.collection}}),await this.roles.init(),await this.orgs.preinit(),await this.preinit(),this.orgs.init(),await this.avatars.init(),this.update(!0),this.collection.onChange(this.#o),await this.sessions.init(),delete this.initOptions,this.isInited=!0,this.#s.resolve(this)}}#o=e=>{switch(e.operationType){case"insert":new P(this,e.fullDocument);break;case"replace":this.get(e.documentKey._id)?.update(e.fullDocument);break;case"update":this.get(e.documentKey._id)?.update(e.updateDescription.updatedFields);break;case"delete":this.get(e.documentKey._id)?.delete()}};load(e){new P(this,e)}sort(){this.isSortRequired=!1,this.sorted=[...this.values()].sort((e,t)=>e.name.last>t.name.last?1:e.name.last<t.name.last?-1:0)}update(e){if(e)for(let t of this.values())t.updateRoles();for(let t of this.values())t.updatePermissions();this.isSortRequired&&this.sort()}#s=new x;whenReady(){return this.#s}async create({email:e,password:t,roles:i,name:s,org:o,job:n,...l}){if(this.byEmail.has(e))throw new Error("User exists");let a=Ue();return await this.collection.insertOne({_id:a,email:e,password:await ve(t),roles:this.isInited?this.roles.cleanUpIds(i):i,name:{first:s.first??"",middle:s.middle??"",last:s.last??""},org:o??null,job:n??"",meta:{},...u(l,["_id"]),createdAt:Date.now()}),a}async updateUser(e,t,i){let s=this.get(e);return s?(t.roles&&(t.roles=s.isRoot?["root"]:this.roles.cleanUpIds(i?k(s.ownRoleIds,i.slaveRoleIds).concat(t.roles):t.roles)),await this.collection.updateOne({_id:e},{$set:t}),!0):!1}async changePassword(e,t){if(!this.has(e))throw new Error("usernotfound");if(!t)throw new Error("emptypasswordisnotallowed");await Promise.all([this.collection.updateOne({_id:e},{$set:{password:await ve(t)}}),this.sessions.collection.deleteMany({user:e})])}async login(e,t,i){let s=this.byEmail.get(e);if(!s)throw new Error("usernotfound");if(!await ke(s.password,t))throw new Error("incorrectpassword");if(!s.abilities.login)throw new Error("userisnotabletologin");return this.sessions.create(s,i)}logout(e){return e.delete(),this.sessions.collection.deleteOne({_id:e._id})}#r(e,t){return e instanceof P&&t instanceof P?e.name.last&&t.name.last?e.name.last>t.name.last?1:e.name.last<t.name.last?-1:0:!e.name.last&&!t.name.last?e.displayLabel>t.displayLabel?1:e.displayLabel<t.displayLabel?-1:0:e.name.last?-1:1:e instanceof m&&t instanceof m?e.title>t.title?1:e.title<t.title?-1:0:e instanceof m?-1:1}sortIds(e){return O(e.map(t=>this.get(t)||this.orgs.get(t)).filter(Boolean).sort(this.#r))}replaceMap=new Map;replaceHandlers=new Set;async replace(e){let t=this.replaceMap.get(e)??null;t&&this.replaceMap.delete(e);for(let i of this.replaceHandlers)await i(e,t)}async deleteUser(e){let{deletedCount:t}=await this.collection.deleteOne({_id:e});return!!t}static init(e,t){return new r(e,t).whenReady()}};export{H as AbilityError,ie as PermissionError,Y as RolesError,te as SubordinationError,ee as UnauthorizedError,le as Users};
4
4
  //# sourceMappingURL=index.js.map