@asaidimu/hestia 1.0.6 → 1.1.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/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@asaidimu/network-client"),t=require("@asaidimu/utils-error"),n=require("@asaidimu/utils-store"),r=require("@asaidimu/utils-sync"),i=require("@asaidimu/query");async function a(e){try{return(await e.clone().json())?.error??null}catch{return null}}function o(e,n){if(n)return new t.SystemError({code:n.code??`UNKNOWN`,message:n.message??`Unknown error`,issues:n.details?.issues});let r=e.error?.message;if(typeof r==`object`&&r){let e=r;return new t.SystemError({code:e.code??`UNKNOWN`,message:e.message??`Unknown error`})}return new t.SystemError({code:`UNKNOWN`,message:r??`Unknown error`})}function s(e){return t.Errors.notFound(e)}function c(e){return t.Errors.permissionDenied(e)}function l(e){return t.Errors.internalError(e)}var u=class{data;status;constructor(e,t){this.data=e,this.status=t}},d=class{baseUrl;apiPrefix;tokens;onAuthStateChanged;raw;constructor(t,n,r,i){this.baseUrl=t,this.apiPrefix=n,this.tokens=r,this.onAuthStateChanged=i,this.raw=(0,e.createNetworkClient)({baseUrl:t,defaultResponseType:`json`,defaultBodyType:`json`})}base(){return this.baseUrl}prefix(){return this.apiPrefix}canonicalPath(e){let t=e.replace(/^\/+/,``);if(this.apiPrefix){let e=this.apiPrefix.replace(/^\/+/,``),n=RegExp(`^${e}/?`);return t=t.replace(n,``),`${e}/${t}`}return t}async request(e,n,r,i){let s=this.canonicalPath(n),c={};i?.headers&&(c.headers={...i.headers}),i?.responseType&&(c.responseType=i.responseType),i?.bodyType&&(c.bodyType=i.bodyType),i?.signal&&(c.signal=i.signal),c.headers||={};let l;if(e===`GET`)l=await this.raw.get(s,c);else{let t=i?.bodyType?{type:i.bodyType}:void 0;l=await this.raw[e.toLowerCase()](s,r,c,t)}if(l.success||l.status===204)return new u(l.data,l.status);if(l.status===401||l.status===403)throw i?.headers?.[`X-API-Key`]||this.onAuthStateChanged?.(),new t.SystemError({code:`AUTH-002-UNAUTH`,message:`Session expired`});let d=l.raw?await a(l.raw):null;throw o(l,d)}async get(e,t){return this.request(`GET`,e,void 0,t)}async post(e,t,n){return this.request(`POST`,e,t,n)}async patch(e,t,n){return this.request(`PATCH`,e,t,n)}async put(e,t,n){return this.request(`PUT`,e,t,n)}async delete(e,t,n){return this.request(`DELETE`,e,t,n)}async openStream(e,n,r){let i={Accept:`text/event-stream`,...r?.headers??{}},a=`${this.baseUrl.replace(/\/+$/,``)}/${this.canonicalPath(e)}`,o;try{o=await fetch(a,{method:`GET`,headers:i,signal:r?.signal})}catch(e){if(e instanceof Error&&e.name===`AbortError`){n.onClose?.();return}n.onError?.(e instanceof Error?e:Error(String(e)));return}if(o.status===401){this.onAuthStateChanged?.(),n.onError?.(new t.SystemError({code:`AUTH-002-UNAUTH`,message:`Session expired`}));return}if(!o.ok||!o.body){n.onError?.(Error(`Stream request failed with status ${o.status}`));return}n.onOpen?.();let s=o.body.getReader(),c=new TextDecoder,l=``;try{for(;;){let{done:e,value:t}=await s.read();if(e)break;l+=c.decode(t,{stream:!0});let r=l.indexOf(`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@asaidimu/network-client"),t=require("@asaidimu/utils-error"),n=require("@asaidimu/utils-store"),r=require("@asaidimu/utils-sync"),i=require("@asaidimu/query");async function a(e){try{return(await e.clone().json())?.error??null}catch{return null}}function o(e,n){if(n)return new t.SystemError({code:n.code??`UNKNOWN`,message:n.message??`Unknown error`,issues:n.details?.issues});let r=e.error?.message;if(typeof r==`object`&&r){let e=r;return new t.SystemError({code:e.code??`UNKNOWN`,message:e.message??`Unknown error`})}return new t.SystemError({code:`UNKNOWN`,message:r??`Unknown error`})}function s(e){return t.Errors.notFound(e)}function c(e){return t.Errors.permissionDenied(e)}function l(e){return t.Errors.internalError(e)}var u=class{data;status;constructor(e,t){this.data=e,this.status=t}},d=class{baseUrl;apiPrefix;provider;onAuthStateChanged;raw;heartbeatTimer;defaultHeartbeatInterval=300*1e3;constructor(t,n,r,i){this.baseUrl=t,this.apiPrefix=n,this.provider=r,this.onAuthStateChanged=i,this.raw=(0,e.createNetworkClient)({baseUrl:t,defaultResponseType:`json`,defaultBodyType:`json`})}base(){return this.baseUrl}prefix(){return this.apiPrefix}startHeartbeat(e){this.stopHeartbeat();let t=e??this.defaultHeartbeatInterval;this.heartbeatTimer=setInterval(()=>this.heartbeat(),t)}stopHeartbeat(){this.heartbeatTimer!==void 0&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0)}async heartbeat(){try{let e=this.canonicalPath(`system/core/heartbeat`),t=`${this.baseUrl.replace(/\/+$/,``)}/${e}`;await fetch(t,{method:`GET`,credentials:`include`})}catch{}}canonicalPath(e){let t=e.replace(/^\/+/,``);if(this.apiPrefix){let e=this.apiPrefix.replace(/^\/+/,``),n=RegExp(`^${e}/?`);return t=t.replace(n,``),`${e}/${t}`}return t}async request(e,n,r,i){let s=this.canonicalPath(n),c={};i?.headers&&(c.headers={...i.headers}),i?.responseType&&(c.responseType=i.responseType),i?.bodyType&&(c.bodyType=i.bodyType),i?.signal&&(c.signal=i.signal),c.headers||={};let l;if(e===`GET`)l=await this.raw.get(s,c);else{let t=i?.bodyType?{type:i.bodyType}:void 0;l=await this.raw[e.toLowerCase()](s,r,c,t)}if(l.success||l.status===204)return new u(l.data,l.status);if(l.status===401)throw i?.headers?.[`X-API-Key`]||(await this.provider.clear(),this.onAuthStateChanged?.()),new t.SystemError({code:`AUTH-002-UNAUTH`,message:`Session expired`});let d=l.raw?await a(l.raw):null;throw o(l,d)}async check(e,t,n){return this.request(`POST`,`${e}/check`,t,n)}async get(e,t){return this.request(`GET`,e,void 0,t)}async post(e,t,n){return this.request(`POST`,e,t,n)}async patch(e,t,n){return this.request(`PATCH`,e,t,n)}async put(e,t,n){return this.request(`PUT`,e,t,n)}async delete(e,t,n){return this.request(`DELETE`,e,t,n)}async openStream(e,n,r){let i={Accept:`text/event-stream`,...r?.headers??{}},a=`${this.baseUrl.replace(/\/+$/,``)}/${this.canonicalPath(e)}`,o;try{o=await fetch(a,{method:`GET`,headers:i,signal:r?.signal})}catch(e){if(e instanceof Error&&e.name===`AbortError`){n.onClose?.();return}n.onError?.(e instanceof Error?e:Error(String(e)));return}if(o.status===401){this.onAuthStateChanged?.(),n.onError?.(new t.SystemError({code:`AUTH-002-UNAUTH`,message:`Session expired`}));return}if(!o.ok||!o.body){n.onError?.(Error(`Stream request failed with status ${o.status}`));return}n.onOpen?.();let s=o.body.getReader(),c=new TextDecoder,l=``;try{for(;;){let{done:e,value:t}=await s.read();if(e)break;l+=c.decode(t,{stream:!0});let r=l.indexOf(`
2
2
 
3
3
  `);for(;r!==-1;){let e=l.slice(0,r);l=l.slice(r+2);let t=e.split(`
4
4
  `).filter(e=>e.startsWith(`data:`)).map(e=>e.slice(5).trim());t.length>0&&n.onMessage(t.join(`
5
5
  `)),r=l.indexOf(`
6
6
 
7
- `)}}}catch(e){e instanceof Error&&e.name===`AbortError`||n.onError?.(e instanceof Error?e:Error(String(e)))}finally{n.onClose?.()}}};const f={data:[],loading:!0,page:{number:1,size:20,count:0,total:0,pages:1}};function p(e,t,i,a){let o=i.page??1,s=i.size??20,c=i.sort,l=i.filter,u=new r.Debouncer({delay:50}),d=`${e}_pager_state_`;t.set({[d]:{data:[],loading:!1,error:n.DELETE_SYMBOL,page:{number:1,size:20,count:0,total:0,pages:1}}});let p=e=>{let t=e?.page??o,n=e?.size??s,r={pagination:{type:`offset`,offset:(t-1)*n,limit:n}},i=e?.sort??c;i&&(r.sort=Array.isArray(i)?i:[i]);let a=e?.filter??l;return a&&(r.filters=a),r},m=async e=>(await t.set({[d]:{loading:!0,error:n.DELETE_SYMBOL}}),await new Promise(n=>{n(u.do(async()=>{requestIdleCallback(()=>{requestIdleCallback(async()=>{try{let n=await a(p(e));await t.set({[d]:n})}catch(e){await t.set({[d]:{...f,error:e}})}finally{await t.set({[d]:{loading:!1}})}})})}))})),h=t.select(e=>e[d]),g=h.subscribe(()=>{});return{page:()=>h.get()??f,navigate:async e=>{if(e<1)throw Error(`Page number must be >= 1`);o=e,await m({page:e})},resize:async(e,t)=>{if(e<1)throw Error(`Page size must be >= 1`);s=e,o=t,await m()},sort:async e=>{c=Array.isArray(e)?e:[e],o=1,await m()},filter:async e=>{l=e,o=1,await m()},refresh:async e=>{await Promise.all([new Promise(t=>setTimeout(t,e?.delay||0)),m(e)])},subscribe:e=>h.subscribe(e),invalidate:async()=>{await t.set({[d]:n.DELETE_SYMBOL}),g()},id:()=>d}}var m=class{client;collectionName;defaultLimit;pagerOptions={};pager;constructor(e,t,r=50){this.client=e,this.collectionName=t,this.defaultLimit=r,this.pager=p(t,new n.ReactiveDataStore({}),this.pagerOptions,e=>this.find(e))}name(){return this.collectionName}get queryPath(){return`/system/collections/document/${encodeURIComponent(this.collectionName)}/query`}get documentsPath(){return`/system/collections/document/${encodeURIComponent(this.collectionName)}`}documentPath(e){return`${this.documentsPath}/${encodeURIComponent(e)}`}async find(e){let t=await this.client.post(this.queryPath,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async read(e){try{return(await this.client.get(this.documentPath(e))).data?.data}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){return(await this.client.post(this.documentsPath,e.data)).data.data}async update(e){let t=e.options;return(await this.client.patch(this.documentPath(t),e.data)).data.data}async delete(e){await this.client.delete(this.documentPath(e))}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:this.defaultLimit}})}async upload(e){throw Error(`Upload not supported for collections`)}async subscribe(e,t){throw Error(`Subscription not implemented for dynamic collections`)}async notify(e){throw Error(`Notify not implemented for dynamic collections`)}stream(e,t){throw Error(`Stream not supported for collections`)}page(e){return this.pager}},h=class{client;provider;constructor(e,t){this.client=e,this.provider=t}async health(){return(await this.client.get(`/system/core/health`)).data.data}async login(e,t){let n=(await this.client.post(`/system/auth/session`,{email:e,password:t})).data.data;return this.provider.setIdentity(n.user),n}async register(e,t,n){return(await this.client.post(`/system/auth/user`,{email:e,password:t,name:n})).data.data}async logout(){await this.client.delete(`/system/auth/session`),await this.provider.clear()}async requestPasswordReset(e){await this.client.post(`/system/auth/password`,{email:e})}async confirmPasswordReset(e,t){await this.client.patch(`/system/auth/password`,{password:t,token:e})}async bootstrap(e,t,n){await this.client.patch(`/system/auth/bootstrap`,{password:t,email:n},{headers:{"X-API-Key":e}})}},g=class{client;pagerOptions={};pager;constructor(e){this.client=e,this.pager=p(`users`,new n.ReactiveDataStore({}),this.pagerOptions,e=>this.find(e))}name(){return`users`}async find(e){let t=await this.client.post(`/system/users/user/query`,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1}}}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:50}})}async read(e){try{return(await this.client.get(`/system/users/user/${encodeURIComponent(e)}`)).data?.data}catch(e){if(e?.code===`SYNC-001-NF`)return;throw e}}async update(e){let t=e.options;return(await this.client.patch(`/system/users/user/${encodeURIComponent(t)}`,e.data)).data.data}async delete(e){await this.client.delete(`/system/users/user/${encodeURIComponent(e)}`)}async create(e){throw Error(`User creation requires email/password/name, use register endpoint`)}async upload(e){throw Error(`Upload not supported for users`)}async subscribe(e,t){throw Error(`Subscription not supported for users`)}async notify(e){throw Error(`Notify not supported for users`)}stream(e,t){throw Error(`Stream not supported for users`)}page(e){return this.pager}async changePassword(e,t,n){await this.client.patch(`/system/users/password/${encodeURIComponent(e)}`,{current:t,new:n})}},_=class{client;pager;constructor(e){this.client=e,this.pager=p(`_api_key_`,new n.ReactiveDataStore({}),{},e=>this.find(e))}basePath=`/system/apikeys/key`;async find(e){let t=await this.client.get(this.basePath),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1}}}async list(e){return e?this.find(e):this.find()}async read(e){try{return(await this.client.get(`${this.basePath}/${encodeURIComponent(e)}`)).data?.data}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`INTERNAL_ERROR`&&typeof e?.message==`string`&&e.message.includes(`not found`))return;throw e}}async create(e){return(await this.client.post(this.basePath,e.data)).data.data}async update(e){let t=e.options;return(await this.client.patch(`${this.basePath}/${encodeURIComponent(t)}`,e.data)).data.data}async delete(e){await this.client.delete(`${this.basePath}/${encodeURIComponent(e)}`)}async upload(e){throw Error(`Upload not supported for API keys`)}async subscribe(e,t){throw Error(`Subscription not supported for API keys`)}async notify(e){throw Error(`Notify not supported for API keys`)}stream(e,t){throw Error(`Stream not supported for API keys`)}page(e){return this.pager}async rotate(e){return(await this.client.post(`${this.basePath}/${encodeURIComponent(e)}`)).data.data}};const v=`/system/policies/operation`;var y=class{client;constructor(e){this.client=e}async list(){let e=(await this.client.get(v)).data?.data?.operations??[];return{data:e.map(e=>({data:e,metadata:{}})),loading:!1,page:{number:1,size:e.length,count:e.length,total:e.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${v}/${encodeURIComponent(e)}`);return t.data?.data?{data:t.data.data,metadata:{}}:void 0}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}};const b=`/system/policies/policy`;var x=class{client;pager;constructor(e){this.client=e,this.pager=p(`policies`,new n.ReactiveDataStore({}),{},e=>this.find(e))}async find(e){return this.query(e??{})}async query(e){let t=await this.client.post(`/system/collections/document/_operation_policy_/query`,e),n=t.data?.data??[],r=t.data?.metadata?.page;return{data:n.map(e=>({_id_:e._id_,_metadata_:e._metadata_,id:e._id_,operationName:e.operation??``,ruleName:e.rule??``,enabled:e.enabled??!0,protected:e.protected??!1})),loading:!1,page:r??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async list(e){let t=(await this.client.get(b)).data?.data?.policies??[];return{data:t.map(e=>({data:e,metadata:{}})),loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${b}/${encodeURIComponent(e)}`);return t.data?.data?{data:t.data.data,metadata:{}}:void 0}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){let t=e.options??e.data.name;if(!t)throw Error(`Operation name is required for create`);let n={ruleName:e.data.ruleName??``},r=await this.client.post(`${b}/${encodeURIComponent(t)}`,n);if(r.data?.data)return{data:r.data.data,metadata:{}}}async update(e){let t=e.options;if(!t)throw Error(`Operation name is required for update`);let n=await this.client.patch(`${b}/${encodeURIComponent(t)}`,e.data);if(n.data?.data)return{data:n.data.data,metadata:{}}}async setEnabled(e,t){return{data:(await this.client.patch(`${b}/${encodeURIComponent(e)}`,{enabled:t})).data.data,metadata:{}}}async delete(e){throw Error(`Policies cannot be deleted; disable instead`)}async upload(e){throw Error(`Upload not supported for policies`)}async subscribe(e,t){throw Error(`Subscription not supported for policies`)}async notify(e){throw Error(`Notify not supported for policies`)}stream(e,t){throw Error(`Stream not supported for policies`)}page(e){return this.pager}};const S=`/system/policies/rule`;var C=class{client;constructor(e){this.client=e}async find(e){return this.list()}async list(e){let t=(await this.client.get(S)).data?.data?.rules??[];return{data:t.map(e=>({_id_:e.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...e})),loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${S}/${encodeURIComponent(e)}`);if(!t.data?.data)return;let n=t.data.data;return{_id_:n.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...n}}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){let t=e.options;if(!t)throw Error(`Rule name is required for create`);let n=await this.client.post(`${S}/${encodeURIComponent(t)}`,e.data);if(!n.data?.data)return;let r=n.data.data;return{_id_:r.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...r}}async update(e){let t=e.options;if(!t)throw Error(`Rule name is required for update`);let n=await this.client.patch(`${S}/${encodeURIComponent(t)}`,e.data);if(!n.data?.data)return;let r=n.data.data;return{_id_:r.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...r}}async delete(e){await this.client.delete(`${S}/${encodeURIComponent(e)}`)}async validate(e){return(await this.client.post(`${S}/query`,{expression:e})).data?.data?.valid??!1}async reload(){return(await this.client.get(S)).data.data}async upload(e){throw Error(`Upload not supported for rules`)}async subscribe(e,t){throw Error(`Subscription not supported for rules`)}async notify(e){throw Error(`Notify not supported for rules`)}stream(e,t){throw Error(`Stream not supported for rules`)}page(e){throw Error(`Pagination not supported for rules`)}},w=class{client;baseUrl;pagerOptions={};pager;apiPrefix;constructor(e,t,r=`/api`){this.client=e,this.baseUrl=t,this.apiPrefix=r,this.pager=p(`_audit_log_`,new n.ReactiveDataStore({}),this.pagerOptions,e=>this.find(e))}async find(e){let t=await this.client.post(`/system/audit/log/query`,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:50}})}async read(e){throw Error(`Read by ID not supported for audit logs; use find with filters`)}async create(e){throw Error(`Audit logs are write-only; entries are created by the system`)}async update(e){throw Error(`Audit logs are append-only; updates are not allowed`)}async delete(e){throw Error(`Audit logs are append-only; deletion is not allowed`)}async upload(e){throw Error(`Upload not supported for audit logs`)}async subscribe(e,t){throw Error(`Use stream() for real-time audit log entries`)}async notify(e){throw Error(`Notify not supported for audit logs`)}stream(e,t){let n=this.getStreamUrl(),r=null,i=`active`,a=null,o=async function*(){let e=[];r=new EventSource(n,{withCredentials:!0}),r.onmessage=t=>{for(let n of t.data.split(`
7
+ `)}}}catch(e){e instanceof Error&&e.name===`AbortError`||n.onError?.(e instanceof Error?e:Error(String(e)))}finally{n.onClose?.()}}};const f={data:[],loading:!0,page:{number:1,size:20,count:0,total:0,pages:1}};function p(e,t,i,a){let o=i.page??1,s=i.size??20,c=i.sort,l=i.filter,u=new r.Debouncer({delay:50}),d=`${e}_pager_state_`;t.set({[d]:{data:[],loading:!1,error:n.DELETE_SYMBOL,page:{number:1,size:20,count:0,total:0,pages:1}}});let p=e=>{let t=e?.page??o,n=e?.size??s,r={pagination:{type:`offset`,offset:(t-1)*n,limit:n}},i=e?.sort??c;i&&(r.sort=Array.isArray(i)?i:[i]);let a=e?.filter??l;return a&&(r.filters=a),r},m=async e=>(await t.set({[d]:{loading:!0,error:n.DELETE_SYMBOL}}),await new Promise(n=>{n(u.do(async()=>{requestIdleCallback(()=>{requestIdleCallback(async()=>{try{let n=await a(p(e));await t.set({[d]:n})}catch(e){await t.set({[d]:{...f,error:e}})}finally{await t.set({[d]:{loading:!1}})}})})}))})),h=t.select(e=>e[d]),g=h.subscribe(()=>{});return{page:()=>h.get()??f,navigate:async e=>{if(e<1)throw Error(`Page number must be >= 1`);o=e,await m({page:e})},resize:async(e,t)=>{if(e<1)throw Error(`Page size must be >= 1`);s=e,o=t,await m()},sort:async e=>{c=Array.isArray(e)?e:[e],o=1,await m()},filter:async e=>{l=e,o=1,await m()},refresh:async e=>{await Promise.all([new Promise(t=>setTimeout(t,e?.delay||0)),m(e)])},subscribe:e=>h.subscribe(e),invalidate:async()=>{await t.set({[d]:n.DELETE_SYMBOL}),g()},id:()=>d}}var m=class{client;collectionName;defaultLimit;pagerOptions={};pager;constructor(e,t,r=50){this.client=e,this.collectionName=t,this.defaultLimit=r,this.pager=p(t,new n.ReactiveDataStore({}),this.pagerOptions,e=>this.find(e))}name(){return this.collectionName}get queryPath(){return`/system/collections/document/${encodeURIComponent(this.collectionName)}/query`}get documentsPath(){return`/system/collections/document/${encodeURIComponent(this.collectionName)}`}documentPath(e){return`${this.documentsPath}/${encodeURIComponent(e)}`}async find(e){let t=await this.client.post(this.queryPath,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async read(e){try{return(await this.client.get(this.documentPath(e))).data?.data}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){return(await this.client.post(this.documentsPath,e.data)).data.data}async update(e){let t=e.options;return(await this.client.patch(this.documentPath(t),e.data)).data.data}async delete(e){await this.client.delete(this.documentPath(e))}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:this.defaultLimit}})}async upload(e){throw Error(`Upload not supported for collections`)}async subscribe(e,t){throw Error(`Subscription not implemented for dynamic collections`)}async notify(e){throw Error(`Notify not implemented for dynamic collections`)}stream(e,t){throw Error(`Stream not supported for collections`)}page(e){return this.pager}},h=class{client;provider;constructor(e,t){this.client=e,this.provider=t}async health(){return(await this.client.get(`/system/core/health`)).data.data}async login(e,t){let n=(await this.client.post(`/system/auth/session`,{email:e,password:t})).data.data;return this.provider.setIdentity(n.user),n}async register(e,t,n){return(await this.client.post(`/system/auth/user`,{email:e,password:t,name:n})).data.data}async logout(){await this.client.delete(`/system/auth/session`),await this.provider.clear()}async requestPasswordReset(e){await this.client.post(`/system/auth/password`,{email:e})}async confirmPasswordReset(e,t){await this.client.patch(`/system/auth/password`,{password:t,token:e})}async bootstrap(e,t,n){await this.client.patch(`/system/auth/bootstrap`,{password:t,email:n},{headers:{"X-API-Key":e}})}},g=class{client;pagerOptions={};pager;constructor(e){this.client=e,this.pager=p(`users`,new n.ReactiveDataStore({}),this.pagerOptions,e=>this.find(e))}name(){return`users`}async find(e){let t=await this.client.post(`/system/users/user/query`,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1}}}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:50}})}async read(e){try{return(await this.client.get(`/system/users/user/${encodeURIComponent(e)}`)).data?.data}catch(e){if(e?.code===`SYNC-001-NF`)return;throw e}}async update(e){let t=e.options;return(await this.client.patch(`/system/users/user/${encodeURIComponent(t)}`,e.data)).data.data}async delete(e){await this.client.delete(`/system/users/user/${encodeURIComponent(e)}`)}async create(e){throw Error(`User creation requires email/password/name, use register endpoint`)}async upload(e){throw Error(`Upload not supported for users`)}async subscribe(e,t){throw Error(`Subscription not supported for users`)}async notify(e){throw Error(`Notify not supported for users`)}stream(e,t){throw Error(`Stream not supported for users`)}page(e){return this.pager}async changePassword(e,t,n){await this.client.patch(`/system/users/password/${encodeURIComponent(e)}`,{current:t,new:n})}},_=class{client;pager;constructor(e){this.client=e,this.pager=p(`_api_key_`,new n.ReactiveDataStore({}),{},e=>this.find(e))}basePath=`/system/apikeys/key`;async find(e){let t=await this.client.get(this.basePath),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1}}}async list(e){return e?this.find(e):this.find()}async read(e){try{return(await this.client.get(`${this.basePath}/${encodeURIComponent(e)}`)).data?.data}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`INTERNAL_ERROR`&&typeof e?.message==`string`&&e.message.includes(`not found`))return;throw e}}async create(e){return(await this.client.post(this.basePath,e.data)).data.data}async update(e){let t=e.options;return(await this.client.patch(`${this.basePath}/${encodeURIComponent(t)}`,e.data)).data.data}async delete(e){await this.client.delete(`${this.basePath}/${encodeURIComponent(e)}`)}async upload(e){throw Error(`Upload not supported for API keys`)}async subscribe(e,t){throw Error(`Subscription not supported for API keys`)}async notify(e){throw Error(`Notify not supported for API keys`)}stream(e,t){throw Error(`Stream not supported for API keys`)}page(e){return this.pager}async rotate(e){return(await this.client.post(`${this.basePath}/${encodeURIComponent(e)}`)).data.data}};const v=`/system/policies/operation`;var y=class{client;constructor(e){this.client=e}async list(){let e=(await this.client.get(v)).data?.data?.operations??[];return{data:e.map(e=>({data:e,metadata:{}})),loading:!1,page:{number:1,size:e.length,count:e.length,total:e.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${v}/${encodeURIComponent(e)}`);return t.data?.data?{data:t.data.data,metadata:{}}:void 0}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}};const b=`/system/policies/policy`;var x=class{client;pager;constructor(e){this.client=e,this.pager=p(`policies`,new n.ReactiveDataStore({}),{},e=>this.find(e))}async find(e){return this.query(e??{})}async query(e){let t=await this.client.post(`/system/collections/document/_operation_policy_/query`,e),n=t.data?.data??[],r=t.data?.metadata?.page;return{data:n.map(e=>({_id_:e._id_,_metadata_:e._metadata_,id:e._id_,operationName:e.operation??``,ruleName:e.rule??``,enabled:e.enabled??!0,protected:e.protected??!1})),loading:!1,page:r??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async list(e){let t=(await this.client.get(b)).data?.data?.policies??[];return{data:t.map(e=>({data:e,metadata:{}})),loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${b}/${encodeURIComponent(e)}`);return t.data?.data?{data:t.data.data,metadata:{}}:void 0}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){let t=e.options??e.data.name;if(!t)throw Error(`Operation name is required for create`);let n={ruleName:e.data.ruleName??``},r=await this.client.post(`${b}/${encodeURIComponent(t)}`,n);if(r.data?.data)return{data:r.data.data,metadata:{}}}async update(e){let t=e.options;if(!t)throw Error(`Operation name is required for update`);let n=await this.client.patch(`${b}/${encodeURIComponent(t)}`,e.data);if(n.data?.data)return{data:n.data.data,metadata:{}}}async setEnabled(e,t){return{data:(await this.client.patch(`${b}/${encodeURIComponent(e)}`,{enabled:t})).data.data,metadata:{}}}async delete(e){throw Error(`Policies cannot be deleted; disable instead`)}async upload(e){throw Error(`Upload not supported for policies`)}async subscribe(e,t){throw Error(`Subscription not supported for policies`)}async notify(e){throw Error(`Notify not supported for policies`)}stream(e,t){throw Error(`Stream not supported for policies`)}page(e){return this.pager}};const S=`/system/policies/rule`;var C=class{client;constructor(e){this.client=e}async find(e){return this.list()}async list(e){let t=(await this.client.get(S)).data?.data?.rules??[];return{data:t.map(e=>({_id_:e.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...e})),loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${S}/${encodeURIComponent(e)}`);if(!t.data?.data)return;let n=t.data.data;return{_id_:n.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...n}}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){let t=e.options??e.data.name;if(!t)throw Error(`Rule name is required for create`);let n=await this.client.post(`${S}/${encodeURIComponent(t)}`,e.data);if(!n.data?.data)return;let r=n.data.data;return{_id_:r.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...r}}async update(e){let t=e.options;if(!t)throw Error(`Rule name is required for update`);let n=await this.client.patch(`${S}/${encodeURIComponent(t)}`,e.data);if(!n.data?.data)return;let r=n.data.data;return{_id_:r.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...r}}async delete(e){await this.client.delete(`${S}/${encodeURIComponent(e)}`)}async validate(e){return(await this.client.check(S,e)).data?.data??{valid:!1}}async reload(){return(await this.client.get(S)).data.data}async upload(e){throw Error(`Upload not supported for rules`)}async subscribe(e,t){throw Error(`Subscription not supported for rules`)}async notify(e){throw Error(`Notify not supported for rules`)}stream(e,t){throw Error(`Stream not supported for rules`)}page(e){throw Error(`Pagination not supported for rules`)}},w=class{client;baseUrl;pagerOptions={};pager;apiPrefix;constructor(e,t,r=`/api`){this.client=e,this.baseUrl=t,this.apiPrefix=r,this.pager=p(`_audit_log_`,new n.ReactiveDataStore({}),this.pagerOptions,e=>this.find(e))}async find(e){let t=await this.client.post(`/system/audit/log/query`,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:50}})}async read(e){throw Error(`Read by ID not supported for audit logs; use find with filters`)}async create(e){throw Error(`Audit logs are write-only; entries are created by the system`)}async update(e){throw Error(`Audit logs are append-only; updates are not allowed`)}async delete(e){throw Error(`Audit logs are append-only; deletion is not allowed`)}async upload(e){throw Error(`Upload not supported for audit logs`)}async subscribe(e,t){throw Error(`Use stream() for real-time audit log entries`)}async notify(e){throw Error(`Notify not supported for audit logs`)}stream(e,t){let n=this.getStreamUrl(),r=null,i=`active`,a=null,o=async function*(){let e=[];r=new EventSource(n,{withCredentials:!0}),r.onmessage=t=>{for(let n of t.data.split(`
8
8
  `)){let t=n.trim();if(t)try{let n=JSON.parse(t);n?.data&&e.push(n.data)}catch{}}e.length>0&&a&&(a(),a=null)},r.onerror=()=>{i===`active`&&(i=`completed`),a&&=(a(),null)};try{for(;i===`active`;)e.length>0?yield e.shift():await new Promise(t=>{a=t,e.length>0&&(t(),a=null)})}finally{r?.close(),a&&=(a(),null),i===`active`&&(i=`completed`)}};return{stream:()=>o(),cancel:()=>{i===`active`&&(i=`cancelled`,r?.close())},status:()=>i}}page(e){return this.pager}getStreamUrl(){return`${this.baseUrl}${this.apiPrefix}/system/audit/log/stream`}};function T(e){return{_id_:e.key,_metadata_:{checksum:``,created:e.created_at,updated:e.updated_at??e.created_at,version:1},...e}}function E(e){return{number:1,size:e.length,count:e.length,total:e.length,pages:1}}var D=class{client;ns;pagerOptions={};pager;prefixFilter=``;constructor(e,t){this.client=e,this.ns=t,this.pager=p(`blobs_${t}`,new n.ReactiveDataStore({}),this.pagerOptions,e=>this.find(e))}name(){return this.ns}setPrefix(e){this.prefixFilter=e}basePath(){return`/system/blobs/blob/${encodeURIComponent(this.ns)}`}async find(e){let t=this.prefixFilter||e?.prefix||``,n=e?.limit??e?.pagination?.limit??0,r={};t&&(r.prefix=t),n&&(r.limit=n);let i=(await this.client.post(`${this.basePath()}/query`,r)).data?.data?.blobs??[];return{data:i.map(T),loading:!1,page:E(i),error:void 0}}async read(e){try{let t=await this.client.post(`${this.basePath()}/${encodeURIComponent(e)}/query`);return t.data?.data?T(t.data.data):void 0}catch(e){if(e?.code===`NOT_FOUND`)return;throw e}}async create(e){throw Error(`Use upload() to create blobs`)}async update(e){let t=e.options?.key;if(!t)throw Error(`options.key is required for blob update`);return T((await this.client.patch(`${this.basePath()}/${encodeURIComponent(t)}`,{custom:e.data})).data.data)}async delete(e){await this.client.delete(`${this.basePath()}/${encodeURIComponent(e)}`)}async list(e){return this.find(e??{})}async upload(e){let t=e.options?.key;if(!t)throw Error(`options.key is required for blob upload`);let n={},r=e.options?.contentType||e.file.type;return r&&(n[`Content-Type`]=r),T((await this.client.post(`${this.basePath()}/${encodeURIComponent(t)}`,e.file,{headers:n,bodyType:`blob`})).data.data)}async subscribe(e,t){throw Error(`Subscription not supported for blobs`)}async notify(e){throw Error(`Notify not supported for blobs`)}stream(e,t){throw Error(`Stream not supported for blobs`)}page(e){return this.pager}async download(e){let t=(await this.client.get(`${this.basePath()}/${encodeURIComponent(e)}`,{responseType:`blob`})).data;return{data:t,contentType:t.type}}},O=class{client;apiPrefix;constructor(e,t=`/api`){this.client=e,this.apiPrefix=t}nsBase=`/system/blobs`;async namespaces(){return(await this.client.post(`${this.nsBase}/namespace/query`)).data?.data?.namespaces??[]}async createNamespace(e){return(await this.client.post(`${this.nsBase}/namespace`,e)).data.data}async deleteNamespace(e){await this.client.delete(`${this.nsBase}/namespace/${encodeURIComponent(e)}`)}blob(e,t){return`${this.client.base()}${this.apiPrefix}${this.nsBase}/blob/${encodeURIComponent(e)}/${encodeURIComponent(t)}`}namespace(e){return new D(this.client,e)}},k=class{client;constructor(e){this.client=e}async find(e){let t=((await this.client.get(`/system/collections/collection`)).data?.data??[]).map(e=>({_id_:e.name,_metadata_:{checksum:``,created:e.created,updated:e.updated,version:1},name:e.name,schema:e.schema,created:e.created,updated:e.updated}));return{data:t,loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1}}}async read(e){try{let t=await this.client.get(`/system/collections/collection/${encodeURIComponent(e)}`);if(!t.data)return;let n=t.data.data;return{_id_:n.name,_metadata_:{checksum:``,created:n.created,updated:n.updated,version:1},name:n.name,schema:n.schema,created:n.created,updated:n.updated}}catch(e){if(e?.code===`SYNC-001-NF`)return;throw e}}async create(e){return(await this.client.post(`/system/collections/collection`,e.data)).data.data}async update(e){throw Error(`Collection update not implemented`)}async delete(e){await this.client.delete(`/system/collections/collection/${encodeURIComponent(e)}`)}async list(e){return this.find()}async upload(e){throw Error(`Upload not supported for collections`)}async subscribe(e,t){throw Error(`Subscription not supported for collections`)}async notify(e){throw Error(`Notify not supported for collections`)}stream(e,t){throw Error(`Stream not supported for collections`)}page(e){throw Error(`Pagination not supported for collection metadata; use documents(name)`)}documents(e){return new m(this.client,e)}},A=class{client;constructor(e){this.client=e}async find(e){let t=(await this.client.get(`/system/core/docs`)).data?.data??[];return{data:t,loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1}}}async read(e){throw Error(`Read by ID not supported for capabilities; use find()`)}async create(e){throw Error(`Capabilities are read-only`)}async update(e){throw Error(`Capabilities are read-only`)}async delete(e){throw Error(`Capabilities are read-only`)}async list(e){return this.find()}async upload(e){throw Error(`Upload not supported for capabilities`)}async subscribe(e,t){throw Error(`Subscription not supported for capabilities`)}async notify(e){throw Error(`Notify not supported for capabilities`)}stream(e,t){throw Error(`Stream not supported for capabilities`)}page(e){throw Error(`Pagination not supported for capabilities`)}},j=class{store;client;auth;users;keys;policies;rules;logs;collections;blobs;capabilities;tokenProvider;onAuthStateChanged;constructor(e){this.store=new n.ReactiveDataStore({identity:null},e.persistence);let t={identity:()=>this.store.get().identity,setIdentity:async e=>void await this.store.set({identity:e}),clear:async()=>void await this.store.set({identity:null})},r=e.apiPrefix??`/api`;this.tokenProvider=t,this.client=new d(e.baseUrl,r,t,()=>this.onAuthStateChanged?.()),this.auth=new h(this.client,t),this.users=new g(this.client),this.keys=new _(this.client),this.policies=new x(this.client),this.rules=new C(this.client),this.logs=new w(this.client,e.baseUrl,r),this.collections=new k(this.client),this.blobs=new O(this.client,r),this.capabilities=new A(this.client)}onAuthStateChange(e){this.onAuthStateChanged=e}authenticated(){return this.tokenProvider.identity()!==null}collection(e){return this.collections.documents(e)}};function M(e){let t=`${e.collectionName}_array_pager_state_`,r=new n.ReactiveDataStore({}),a=[...e.initialData??[]],o=`collection`,s,c=e.page??1,l=e.size??20,u=[],d,f,{match:p}=(0,i.createMatcher)(e.customFunctions??{}),{sort:m}=(0,i.createSorter)(),h=r.select(e=>e[t]),g={data:[],loading:!0,error:void 0,page:{number:1,size:l,count:0,total:0,pages:1}},_=()=>({filters:d,sort:u,pagination:{type:`offset`,offset:(c-1)*l,limit:l}}),v=async(n=!0)=>{if(e.fetch){if(f=void 0,n){let e=h.get()??g;await r.set({[t]:{...e,loading:!0,error:void 0}})}try{let t=_(),n=await e.fetch(t);o=n.scope,s=n.total,a=n.replace?[...n.data]:[...a,...n.data]}catch(e){f=e}}let i=y(e.fetch?n:!1);await r.set({[t]:i})},y=e=>{let t=[...a];if(o===`collection`){d&&(t=t.filter(e=>p(e,d))),u.length>0&&(t=m(t,u));let n=t.length,r=Math.ceil(n/l)||1;c>r&&(c=r),c<1&&(c=1);let i=(c-1)*l,a=t.slice(i,i+l);return{data:a,loading:e,error:f,page:{number:c,size:l,count:a.length,total:n,pages:r}}}let n=s??t.length,r=Math.ceil(n/l)||1;return{data:t,loading:e,error:f,page:{number:c,size:l,count:t.length,total:n,pages:r}}};return v(!0),{id:()=>t,page:()=>h.get()??g,navigate:async e=>{if(e<1)throw Error(`Page number must be >= 1`);c=e,await v(!0)},resize:async(e,t)=>{if(e<1)throw Error(`Page size must be >= 1`);l=e,c=t,await v(!0)},sort:async e=>{u=Array.isArray(e)?e:[e],c=1,await v(!0)},filter:async e=>{d=e,c=1,await v(!0)},refresh:async e=>{let n=h.get()??g;await r.set({[t]:{...n,loading:!0}});let i=e?.delay??600;await Promise.all([new Promise(e=>setTimeout(e,i)),v(!1)]);let a=h.get()??g;await r.set({[t]:{...a,loading:!1}})},subscribe:e=>h.subscribe(t=>{e(t)}),invalidate:async()=>{await r.set({[t]:n.DELETE_SYMBOL}),a=[]}}}exports.BlobNamespace=D,exports.HestiaAuth=h,exports.HestiaBlobClient=O,exports.HestiaClient=j,exports.HestiaCollection=m,exports.HestiaCollections=k,exports.HestiaKeyStore=_,exports.HestiaLogs=w,exports.HestiaNetworkClient=d,exports.HestiaOperations=y,exports.HestiaPolicies=x,exports.HestiaResponse=u,exports.HestiaRules=C,exports.HestiaUsers=g,exports.createArrayPager=M,exports.createPagedController=p,exports.internalError=l,exports.notFound=s,exports.parseErrorBody=a,exports.permissionDenied=c,exports.toSystemError=o;
package/index.d.cts CHANGED
@@ -4,17 +4,17 @@ import { Issue, SystemError } from "@asaidimu/utils-error";
4
4
  import { DataStore, ReactiveDataStore } from "@asaidimu/utils-store";
5
5
  import { SchemaDefinition } from "@asaidimu/utils-schema";
6
6
  //#region core/types.d.ts
7
- interface DocumentMetadata {
7
+ interface DocumentMetadata$1 {
8
8
  checksum: string;
9
9
  created: string;
10
10
  updated: string;
11
11
  version: number;
12
12
  }
13
- interface BaseDocument {
13
+ interface BaseDocument$1 {
14
14
  _id_: string;
15
- _metadata_: DocumentMetadata;
15
+ _metadata_: DocumentMetadata$1;
16
16
  }
17
- type Document<T extends Record<string, any>> = BaseDocument & T;
17
+ type Document<T extends Record<string, any>> = BaseDocument$1 & T;
18
18
  /**
19
19
  * Provides comprehensive pagination information for a collection of records.
20
20
  */
@@ -270,12 +270,12 @@ declare class HestiaResponse<T> {
270
270
  readonly status: number;
271
271
  constructor(data: T, status: number);
272
272
  }
273
- type BodyType = "json" | "form" | "text" | "blob" | "stream" | "auto";
274
- type ResponseType = "json" | "text" | "blob" | "arrayBuffer" | "formData" | "auto";
275
- interface RequestOptions {
273
+ type BodyType$1 = "json" | "form" | "text" | "blob" | "stream" | "auto";
274
+ type ResponseType$1 = "json" | "text" | "blob" | "arrayBuffer" | "formData" | "auto";
275
+ interface RequestOptions$1 {
276
276
  headers?: Record<string, string>;
277
- responseType?: ResponseType;
278
- bodyType?: BodyType;
277
+ responseType?: ResponseType$1;
278
+ bodyType?: BodyType$1;
279
279
  signal?: AbortSignal;
280
280
  }
281
281
  interface StreamHandlers {
@@ -291,19 +291,29 @@ interface StreamOptions {
291
291
  declare class HestiaNetworkClient {
292
292
  private baseUrl;
293
293
  private apiPrefix;
294
- private tokens;
294
+ private provider;
295
295
  private onAuthStateChanged?;
296
296
  private raw;
297
- constructor(baseUrl: string, apiPrefix: string, tokens: IdentityProvider, onAuthStateChanged?: (() => void) | undefined);
297
+ private heartbeatTimer?;
298
+ private defaultHeartbeatInterval;
299
+ constructor(baseUrl: string, apiPrefix: string, provider: IdentityProvider, onAuthStateChanged?: (() => void) | undefined);
298
300
  base(): string;
299
301
  prefix(): string;
302
+ /** Start periodic heartbeat to keep the session alive.
303
+ * Sends a lightweight GET to the health-check endpoint at the given
304
+ * interval (default 5 min). The server's sliding-window refresh logic
305
+ * renews the session cookie automatically. */
306
+ startHeartbeat(intervalMs?: number): void;
307
+ stopHeartbeat(): void;
308
+ private heartbeat;
300
309
  private canonicalPath;
301
310
  private request;
302
- get<T>(path: string, options?: RequestOptions): Promise<HestiaResponse<T>>;
303
- post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse<T>>;
304
- patch<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse<T>>;
305
- put<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse<T>>;
306
- delete<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse<T>>;
311
+ check<T>(path: string, body?: unknown, options?: RequestOptions$1): Promise<HestiaResponse<T>>;
312
+ get<T>(path: string, options?: RequestOptions$1): Promise<HestiaResponse<T>>;
313
+ post<T>(path: string, body?: unknown, options?: RequestOptions$1): Promise<HestiaResponse<T>>;
314
+ patch<T>(path: string, body?: unknown, options?: RequestOptions$1): Promise<HestiaResponse<T>>;
315
+ put<T>(path: string, body?: unknown, options?: RequestOptions$1): Promise<HestiaResponse<T>>;
316
+ delete<T>(path: string, body?: unknown, options?: RequestOptions$1): Promise<HestiaResponse<T>>;
307
317
  openStream(path: string, handlers: StreamHandlers, options?: StreamOptions): Promise<void>;
308
318
  }
309
319
  //#endregion
@@ -628,7 +638,7 @@ declare class HestiaRules implements DocumentStore<PolicyRule, Record<string, un
628
638
  options?: string;
629
639
  }): Promise<Document<PolicyRule> | undefined>;
630
640
  delete(name: string): Promise<void>;
631
- validate(expression: string): Promise<boolean>;
641
+ validate(request: ValidateRuleRequest): Promise<ValidateRuleResult>;
632
642
  reload(): Promise<ReloadResult>;
633
643
  upload(_props: {
634
644
  file: File;
@@ -835,6 +845,340 @@ declare class HestiaCollections implements DocumentStore<CollectionMeta, Record<
835
845
  documents<T extends Record<string, any>>(collectionName: string): HestiaCollection<T>;
836
846
  }
837
847
  //#endregion
848
+ //#region dist/index.d.mts
849
+ //#region core/types.d.ts
850
+ interface DocumentMetadata {
851
+ checksum: string;
852
+ created: string;
853
+ updated: string;
854
+ version: number;
855
+ }
856
+ interface BaseDocument {
857
+ _id_: string;
858
+ _metadata_: DocumentMetadata;
859
+ }
860
+ type Document$1<T extends Record<string, any>> = BaseDocument & T;
861
+ /**
862
+ * Provides comprehensive pagination information for a collection of records.
863
+ */
864
+ type PaginationInfo$1 = {
865
+ /** The current page number (1-based). */
866
+ number: number;
867
+ /** The maximum number of items requested per page. */
868
+ size: number;
869
+ /** The number of items in the current page */
870
+ count: number;
871
+ /** The total count of all items across all pages. */
872
+ total: number;
873
+ /** The total number of available pages. */
874
+ pages: number;
875
+ };
876
+ /**
877
+ * Represents a single paginated response containing a list of records and pagination details.
878
+ * @template T The type of the records in the page.
879
+ */
880
+ interface Page$1<T extends Record<string, any>> {
881
+ /** The array of records for the current page. */
882
+ data: Document$1<T>[];
883
+ /** Indicates if the data query is currently loading. */
884
+ loading: boolean;
885
+ /** An error object if the query failed, otherwise `undefined`. */
886
+ error?: any | undefined;
887
+ /** Pagination metadata providing details about the current page and total collection. */
888
+ page: PaginationInfo$1;
889
+ }
890
+ interface PagerRefreshOptions$1 {
891
+ sort?: SortConfiguration | SortConfiguration[];
892
+ filter?: QueryFilter;
893
+ delay?: number;
894
+ size?: number;
895
+ page?: number;
896
+ }
897
+ /**
898
+ * Represents the complete state and control mechanisms for consuming paginated data.
899
+ * @template T The type of the records in the page (`TableRowData` or an extension).
900
+ */
901
+ interface PagedData$1<T extends Record<string, any>> {
902
+ id: () => string;
903
+ /** The current paginated data, or `undefined` if not found or still loading. */
904
+ page: () => Page$1<T>;
905
+ /** Function to fetch a specific page of data.
906
+ * @param page The 1-based page number to fetch.
907
+ */
908
+ navigate: (page: number) => Promise<void>;
909
+ sort: (sort: SortConfiguration<T> | SortConfiguration<T>[]) => Promise<void>;
910
+ filter: (filter?: QueryFilter<T>) => Promise<void>;
911
+ /**
912
+ * Function to change the page size of the data
913
+ */
914
+ resize: (size: number, page: number) => Promise<void>;
915
+ /**
916
+ * Function to force a refresh of the current page data, optionally with a delay.
917
+ * @param delay Optional delay in milliseconds before the refresh operation starts.
918
+ */
919
+ refresh: (opts?: PagerRefreshOptions$1) => Promise<void>;
920
+ /**
921
+ * Subscribes to page changes.
922
+ * The callback is invoked immediately with the current page, and then on every
923
+ * subsequent change (navigation, resize, SSE patch, refresh).
924
+ *
925
+ * @param listener A function that receives the current Page<T>.
926
+ * @returns An unsubscribe function.
927
+ */
928
+ subscribe: (listener: (page: Page$1<T>) => void) => () => void;
929
+ /**
930
+ * Invalidates the pagination controller, cleaning up any cached resources
931
+ * (e.g., store subscriptions, in‑flight requests) and removing internal state.
932
+ * After calling `invalidate()`, the controller should no longer be used.
933
+ *
934
+ * This is useful when the component using the pager is unmounted or when
935
+ * you need to reset the pagination state completely.
936
+ */
937
+ invalidate: () => void;
938
+ }
939
+ /**
940
+ * Represents an event emitted by the store, typically for notifications or state changes.
941
+ */
942
+ interface StoreEvent$1 {
943
+ /** The scope of the event, indicating its type and context. Custom scopes are allowed. */
944
+ scope: string;
945
+ /** Optional payload carrying data related to the event. */
946
+ payload?: any;
947
+ }
948
+ /**
949
+ * Defines the core interface for interacting with a remote data store.
950
+ * @template T The type of the records managed by the store, extending Record.
951
+ * @template TFindOptions Options for the find operation.
952
+ * @template TReadOptions Options for the read operation.
953
+ * @template TListOptions Options for the list operation.
954
+ * @template TPageOptions Options for the paging operation.
955
+ * @template TDeleteOptions Options for the delete operation.
956
+ * @template TUpdateOptions Options for the update operation.
957
+ * @template TCreateOptions Options for the create operation.
958
+ * @template TUploadOptions Options for the upload operation.
959
+ * @template TStreamOptions Options for the stream operation.
960
+ */
961
+ interface DocumentStore$1<T extends Record<string, any>, TFindOptions = Record<string, unknown>, TReadOptions = Record<string, unknown>, TListOptions = Record<string, unknown>, TPageOptions = Record<string, unknown>, TDeleteOptions = Record<string, unknown>, TUpdateOptions = Record<string, unknown>, TCreateOptions = Record<string, unknown>, TUploadOptions = Record<string, unknown>, TStreamOptions = Record<string, unknown>> {
962
+ /**
963
+ * Finds records based on provided options, returning a paginated result.
964
+ * @param options The options for the find operation.
965
+ * @returns A promise that resolves to a Page of records.
966
+ */
967
+ find: (options: TFindOptions) => Promise<Page$1<T>>;
968
+ /**
969
+ * Reads a single record by its identifier or other read options.
970
+ * @param options The options for the read operation, typically including an ID.
971
+ * @returns A promise that resolves to the record or undefined if not found.
972
+ */
973
+ read: (options: TReadOptions) => Promise<Document$1<T> | undefined>;
974
+ /**
975
+ * Lists records based on provided options, returning a paginated result.
976
+ * @param options The options for the list operation.
977
+ * @returns A promise that resolves to a Page of records.
978
+ */
979
+ list: (options: TListOptions) => Promise<Page$1<T>>;
980
+ /**
981
+ * Deletes a record based on provided options, typically including an ID.
982
+ * @param options The options for the delete operation.
983
+ * @returns A promise that resolves when the deletion is complete.
984
+ */
985
+ delete: (options: TDeleteOptions) => Promise<void>;
986
+ /**
987
+ * Updates an existing record.
988
+ * @param props An object containing the ID of the record to update, the partial data, and optional update options.
989
+ * @returns A promise that resolves to the updated record or undefined if not found.
990
+ */
991
+ update: (props: {
992
+ data: Partial<T>;
993
+ options?: TUpdateOptions;
994
+ }) => Promise<Document$1<T> | undefined>;
995
+ /**
996
+ * Creates a new record.
997
+ * @param props An object containing the data for the new record and optional create options.
998
+ * @returns A promise that resolves to the newly created record or undefined if creation failed.
999
+ */
1000
+ create: (props: {
1001
+ data: Partial<T>;
1002
+ options?: TCreateOptions;
1003
+ }) => Promise<Document$1<T> | undefined>;
1004
+ /**
1005
+ * Uploads a file associated with a record. Optionally updates the record with upload details.
1006
+ * @param props An object containing the file to upload and optional upload options.
1007
+ * @returns A promise that resolves to the updated record after upload or undefined if upload failed.
1008
+ */
1009
+ upload: (props: {
1010
+ file: File;
1011
+ options?: TUploadOptions;
1012
+ }) => Promise<Document$1<T> | undefined>;
1013
+ /**
1014
+ * Subscribes to store events for a given scope.
1015
+ * @param scope The event scope to subscribe to (e.g., 'todos:created:success', '*').
1016
+ * @param callback The function to call when an event matching the scope is received.
1017
+ * @returns A promise that resolves to an unsubscribe function. Call this function to stop receiving events.
1018
+ */
1019
+ subscribe(scope: string, callback: (event: StoreEvent$1) => void): Promise<() => void>;
1020
+ /**
1021
+ * Notifies the store of an event, which can then be broadcast to subscribers.
1022
+ * @param event The StoreEvent to notify.
1023
+ * @returns A promise that resolves when the notification has been processed.
1024
+ */
1025
+ notify: (event: StoreEvent$1) => Promise<void>;
1026
+ /**
1027
+ * Establishes a stream of records based on provided options.
1028
+ * @param options Options for configuring the stream (e.g., batch size, delay, filters).
1029
+ * @param onStreamChange A callback function that is called when the stream's status changes.
1030
+ * @returns An object containing the async iterable stream, a cancel function, and a status getter.
1031
+ */
1032
+ stream: (options: TStreamOptions, onStreamChange: () => void) => {
1033
+ /** An async iterable that yields records as they become available in the stream. */
1034
+ stream: () => AsyncIterable<Document$1<T>>;
1035
+ /** A function to call to cancel the ongoing stream. */
1036
+ cancel: () => void;
1037
+ /** A getter function that returns the current status of the stream ('active', 'cancelled', or 'completed'). */
1038
+ status: () => "active" | "cancelled" | "completed";
1039
+ };
1040
+ /**
1041
+ * Creates a paginated data controller for this store.
1042
+ *
1043
+ * @param options - The pagination options, whose type is defined by the
1044
+ * store's `TPageOptions` generic parameter. This lets you
1045
+ * pass any configuration (e.g., filters, sorting, custom
1046
+ * pagination metadata) that your store implementation needs.
1047
+ * @returns A `PagedData<T>` controller that manages loading, navigation,
1048
+ * resizing, and refresh.
1049
+ *
1050
+ * @example
1051
+ * // Define your store with a custom TPageOptions type
1052
+ * interface MyTodoStore extends DocumentStore<
1053
+ * Todo,
1054
+ * FindOptions,
1055
+ * ReadOptions,
1056
+ * ListOptions,
1057
+ * { page: number; size: number; sort?: string; filter?: string }
1058
+ * > {}
1059
+ *
1060
+ * // Use it
1061
+ * const todosPaged = myTodoStore.page({
1062
+ * page: 1,
1063
+ * size: 10,
1064
+ * sort: 'createdAt',
1065
+ * filter: 'done:false'
1066
+ * });
1067
+ *
1068
+ * // Get current page state
1069
+ * const { data, loading, page } = todosPaged.page();
1070
+ * console.log(`Page ${page.number} of ${page.pages}`);
1071
+ *
1072
+ * // Navigate
1073
+ * await todosPaged.navigate(2);
1074
+ */
1075
+ page(options: TPageOptions): PagedData$1<T>;
1076
+ }
1077
+ //#endregion
1078
+ //#region system/identity/types.d.ts
1079
+ interface UserData$1 {
1080
+ email: string;
1081
+ name: string;
1082
+ verified: boolean;
1083
+ permissions: string[];
1084
+ deleted?: string | null;
1085
+ }
1086
+ type UserIdentity$1 = Document$1<UserData$1>;
1087
+ //#endregion
1088
+ //#region core/client.d.ts
1089
+ interface IdentityProvider$1 {
1090
+ identity(): UserIdentity$1 | null;
1091
+ setIdentity(id: UserIdentity$1 | null): Promise<void>;
1092
+ clear(): Promise<void>;
1093
+ }
1094
+ declare class HestiaResponse$1<T> {
1095
+ readonly data: T;
1096
+ readonly status: number;
1097
+ constructor(data: T, status: number);
1098
+ }
1099
+ type BodyType = "json" | "form" | "text" | "blob" | "stream" | "auto";
1100
+ type ResponseType = "json" | "text" | "blob" | "arrayBuffer" | "formData" | "auto";
1101
+ interface RequestOptions {
1102
+ headers?: Record<string, string>;
1103
+ responseType?: ResponseType;
1104
+ bodyType?: BodyType;
1105
+ signal?: AbortSignal;
1106
+ }
1107
+ interface StreamHandlers$1 {
1108
+ onMessage: (data: string) => void;
1109
+ onError?: (err: Error) => void;
1110
+ onOpen?: () => void;
1111
+ onClose?: () => void;
1112
+ }
1113
+ interface StreamOptions$1 {
1114
+ headers?: Record<string, string>;
1115
+ signal?: AbortSignal;
1116
+ }
1117
+ declare class HestiaNetworkClient$1 {
1118
+ private baseUrl;
1119
+ private apiPrefix;
1120
+ private provider;
1121
+ private onAuthStateChanged?;
1122
+ private raw;
1123
+ private heartbeatTimer?;
1124
+ private defaultHeartbeatInterval;
1125
+ constructor(baseUrl: string, apiPrefix: string, provider: IdentityProvider$1, onAuthStateChanged?: (() => void) | undefined);
1126
+ base(): string;
1127
+ prefix(): string;
1128
+ /** Start periodic heartbeat to keep the session alive.
1129
+ * Sends a lightweight GET to the health-check endpoint at the given
1130
+ * interval (default 5 min). The server's sliding-window refresh logic
1131
+ * renews the session cookie automatically. */
1132
+ startHeartbeat(intervalMs?: number): void;
1133
+ stopHeartbeat(): void;
1134
+ private heartbeat;
1135
+ private canonicalPath;
1136
+ private request;
1137
+ check<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse$1<T>>;
1138
+ get<T>(path: string, options?: RequestOptions): Promise<HestiaResponse$1<T>>;
1139
+ post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse$1<T>>;
1140
+ patch<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse$1<T>>;
1141
+ put<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse$1<T>>;
1142
+ delete<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse$1<T>>;
1143
+ openStream(path: string, handlers: StreamHandlers$1, options?: StreamOptions$1): Promise<void>;
1144
+ }
1145
+ //#endregion
1146
+ //#region core/collection.d.ts
1147
+ declare class HestiaCollection$1<T extends Record<string, any>> implements DocumentStore$1<T, Record<string, unknown>, string, Record<string, unknown>, Record<string, unknown>, string, string, Record<string, unknown>> {
1148
+ private client;
1149
+ private collectionName;
1150
+ private defaultLimit;
1151
+ private pagerOptions;
1152
+ private pager;
1153
+ constructor(client: HestiaNetworkClient$1, collectionName: string, defaultLimit?: number);
1154
+ name(): string;
1155
+ private get queryPath();
1156
+ private get documentsPath();
1157
+ private documentPath;
1158
+ find(query?: Record<string, unknown>): Promise<Page$1<T>>;
1159
+ read(id: string): Promise<Document$1<T> | undefined>;
1160
+ create(props: {
1161
+ data: Partial<T>;
1162
+ }): Promise<Document$1<T> | undefined>;
1163
+ update(props: {
1164
+ data: Partial<T>;
1165
+ options?: string;
1166
+ }): Promise<Document$1<T> | undefined>;
1167
+ delete(id: string): Promise<void>;
1168
+ list(options?: Record<string, unknown>): Promise<Page$1<T>>;
1169
+ upload(_props: {
1170
+ file: File;
1171
+ }): Promise<Document$1<T> | undefined>;
1172
+ subscribe(_scope: string, _callback: (event: StoreEvent$1) => void): Promise<() => void>;
1173
+ notify(_event: StoreEvent$1): Promise<void>;
1174
+ stream(_options: Record<string, unknown>, _onStreamChange: () => void): {
1175
+ stream: () => AsyncIterable<Document$1<T>>;
1176
+ cancel: () => void;
1177
+ status: () => "active" | "cancelled" | "completed";
1178
+ };
1179
+ page(_options?: Record<string, unknown>): PagedData$1<T>;
1180
+ }
1181
+ //#endregion
838
1182
  //#region node_modules/@asaidimu/utils-persistence/index.d.ts
839
1183
  interface SimplePersistence<T> {
840
1184
  /**
@@ -944,7 +1288,7 @@ declare class HestiaClient {
944
1288
  constructor(config: HestiaConfig);
945
1289
  onAuthStateChange(callback: () => void): void;
946
1290
  authenticated(): boolean;
947
- collection<T extends Record<string, any>>(name: string): HestiaCollection<T>;
1291
+ collection<T extends Record<string, any>>(name: string): HestiaCollection$1<T>;
948
1292
  }
949
1293
  //#endregion
950
1294
  //#region utils/pager.d.ts
package/index.d.mts CHANGED
@@ -291,14 +291,24 @@ interface StreamOptions {
291
291
  declare class HestiaNetworkClient {
292
292
  private baseUrl;
293
293
  private apiPrefix;
294
- private tokens;
294
+ private provider;
295
295
  private onAuthStateChanged?;
296
296
  private raw;
297
- constructor(baseUrl: string, apiPrefix: string, tokens: IdentityProvider, onAuthStateChanged?: (() => void) | undefined);
297
+ private heartbeatTimer?;
298
+ private defaultHeartbeatInterval;
299
+ constructor(baseUrl: string, apiPrefix: string, provider: IdentityProvider, onAuthStateChanged?: (() => void) | undefined);
298
300
  base(): string;
299
301
  prefix(): string;
302
+ /** Start periodic heartbeat to keep the session alive.
303
+ * Sends a lightweight GET to the health-check endpoint at the given
304
+ * interval (default 5 min). The server's sliding-window refresh logic
305
+ * renews the session cookie automatically. */
306
+ startHeartbeat(intervalMs?: number): void;
307
+ stopHeartbeat(): void;
308
+ private heartbeat;
300
309
  private canonicalPath;
301
310
  private request;
311
+ check<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse<T>>;
302
312
  get<T>(path: string, options?: RequestOptions): Promise<HestiaResponse<T>>;
303
313
  post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse<T>>;
304
314
  patch<T>(path: string, body?: unknown, options?: RequestOptions): Promise<HestiaResponse<T>>;
@@ -628,7 +638,7 @@ declare class HestiaRules implements DocumentStore<PolicyRule, Record<string, un
628
638
  options?: string;
629
639
  }): Promise<Document<PolicyRule> | undefined>;
630
640
  delete(name: string): Promise<void>;
631
- validate(expression: string): Promise<boolean>;
641
+ validate(request: ValidateRuleRequest): Promise<ValidateRuleResult>;
632
642
  reload(): Promise<ReloadResult>;
633
643
  upload(_props: {
634
644
  file: File;
package/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
- import{createNetworkClient as e}from"@asaidimu/network-client";import{Errors as t,SystemError as n}from"@asaidimu/utils-error";import{DELETE_SYMBOL as r,ReactiveDataStore as i}from"@asaidimu/utils-store";import{Debouncer as a}from"@asaidimu/utils-sync";import{createMatcher as o,createSorter as s}from"@asaidimu/query";async function c(e){try{return(await e.clone().json())?.error??null}catch{return null}}function l(e,t){if(t)return new n({code:t.code??`UNKNOWN`,message:t.message??`Unknown error`,issues:t.details?.issues});let r=e.error?.message;if(typeof r==`object`&&r){let e=r;return new n({code:e.code??`UNKNOWN`,message:e.message??`Unknown error`})}return new n({code:`UNKNOWN`,message:r??`Unknown error`})}function u(e){return t.notFound(e)}function d(e){return t.permissionDenied(e)}function f(e){return t.internalError(e)}var p=class{data;status;constructor(e,t){this.data=e,this.status=t}},m=class{baseUrl;apiPrefix;tokens;onAuthStateChanged;raw;constructor(t,n,r,i){this.baseUrl=t,this.apiPrefix=n,this.tokens=r,this.onAuthStateChanged=i,this.raw=e({baseUrl:t,defaultResponseType:`json`,defaultBodyType:`json`})}base(){return this.baseUrl}prefix(){return this.apiPrefix}canonicalPath(e){let t=e.replace(/^\/+/,``);if(this.apiPrefix){let e=this.apiPrefix.replace(/^\/+/,``),n=RegExp(`^${e}/?`);return t=t.replace(n,``),`${e}/${t}`}return t}async request(e,t,r,i){let a=this.canonicalPath(t),o={};i?.headers&&(o.headers={...i.headers}),i?.responseType&&(o.responseType=i.responseType),i?.bodyType&&(o.bodyType=i.bodyType),i?.signal&&(o.signal=i.signal),o.headers||={};let s;if(e===`GET`)s=await this.raw.get(a,o);else{let t=i?.bodyType?{type:i.bodyType}:void 0;s=await this.raw[e.toLowerCase()](a,r,o,t)}if(s.success||s.status===204)return new p(s.data,s.status);if(s.status===401||s.status===403)throw i?.headers?.[`X-API-Key`]||this.onAuthStateChanged?.(),new n({code:`AUTH-002-UNAUTH`,message:`Session expired`});let u=s.raw?await c(s.raw):null;throw l(s,u)}async get(e,t){return this.request(`GET`,e,void 0,t)}async post(e,t,n){return this.request(`POST`,e,t,n)}async patch(e,t,n){return this.request(`PATCH`,e,t,n)}async put(e,t,n){return this.request(`PUT`,e,t,n)}async delete(e,t,n){return this.request(`DELETE`,e,t,n)}async openStream(e,t,r){let i={Accept:`text/event-stream`,...r?.headers??{}},a=`${this.baseUrl.replace(/\/+$/,``)}/${this.canonicalPath(e)}`,o;try{o=await fetch(a,{method:`GET`,headers:i,signal:r?.signal})}catch(e){if(e instanceof Error&&e.name===`AbortError`){t.onClose?.();return}t.onError?.(e instanceof Error?e:Error(String(e)));return}if(o.status===401){this.onAuthStateChanged?.(),t.onError?.(new n({code:`AUTH-002-UNAUTH`,message:`Session expired`}));return}if(!o.ok||!o.body){t.onError?.(Error(`Stream request failed with status ${o.status}`));return}t.onOpen?.();let s=o.body.getReader(),c=new TextDecoder,l=``;try{for(;;){let{done:e,value:n}=await s.read();if(e)break;l+=c.decode(n,{stream:!0});let r=l.indexOf(`
1
+ import{createNetworkClient as e}from"@asaidimu/network-client";import{Errors as t,SystemError as n}from"@asaidimu/utils-error";import{DELETE_SYMBOL as r,ReactiveDataStore as i}from"@asaidimu/utils-store";import{Debouncer as a}from"@asaidimu/utils-sync";import{createMatcher as o,createSorter as s}from"@asaidimu/query";async function c(e){try{return(await e.clone().json())?.error??null}catch{return null}}function l(e,t){if(t)return new n({code:t.code??`UNKNOWN`,message:t.message??`Unknown error`,issues:t.details?.issues});let r=e.error?.message;if(typeof r==`object`&&r){let e=r;return new n({code:e.code??`UNKNOWN`,message:e.message??`Unknown error`})}return new n({code:`UNKNOWN`,message:r??`Unknown error`})}function u(e){return t.notFound(e)}function d(e){return t.permissionDenied(e)}function f(e){return t.internalError(e)}var p=class{data;status;constructor(e,t){this.data=e,this.status=t}},m=class{baseUrl;apiPrefix;provider;onAuthStateChanged;raw;heartbeatTimer;defaultHeartbeatInterval=300*1e3;constructor(t,n,r,i){this.baseUrl=t,this.apiPrefix=n,this.provider=r,this.onAuthStateChanged=i,this.raw=e({baseUrl:t,defaultResponseType:`json`,defaultBodyType:`json`})}base(){return this.baseUrl}prefix(){return this.apiPrefix}startHeartbeat(e){this.stopHeartbeat();let t=e??this.defaultHeartbeatInterval;this.heartbeatTimer=setInterval(()=>this.heartbeat(),t)}stopHeartbeat(){this.heartbeatTimer!==void 0&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0)}async heartbeat(){try{let e=this.canonicalPath(`system/core/heartbeat`),t=`${this.baseUrl.replace(/\/+$/,``)}/${e}`;await fetch(t,{method:`GET`,credentials:`include`})}catch{}}canonicalPath(e){let t=e.replace(/^\/+/,``);if(this.apiPrefix){let e=this.apiPrefix.replace(/^\/+/,``),n=RegExp(`^${e}/?`);return t=t.replace(n,``),`${e}/${t}`}return t}async request(e,t,r,i){let a=this.canonicalPath(t),o={};i?.headers&&(o.headers={...i.headers}),i?.responseType&&(o.responseType=i.responseType),i?.bodyType&&(o.bodyType=i.bodyType),i?.signal&&(o.signal=i.signal),o.headers||={};let s;if(e===`GET`)s=await this.raw.get(a,o);else{let t=i?.bodyType?{type:i.bodyType}:void 0;s=await this.raw[e.toLowerCase()](a,r,o,t)}if(s.success||s.status===204)return new p(s.data,s.status);if(s.status===401)throw i?.headers?.[`X-API-Key`]||(await this.provider.clear(),this.onAuthStateChanged?.()),new n({code:`AUTH-002-UNAUTH`,message:`Session expired`});let u=s.raw?await c(s.raw):null;throw l(s,u)}async check(e,t,n){return this.request(`POST`,`${e}/check`,t,n)}async get(e,t){return this.request(`GET`,e,void 0,t)}async post(e,t,n){return this.request(`POST`,e,t,n)}async patch(e,t,n){return this.request(`PATCH`,e,t,n)}async put(e,t,n){return this.request(`PUT`,e,t,n)}async delete(e,t,n){return this.request(`DELETE`,e,t,n)}async openStream(e,t,r){let i={Accept:`text/event-stream`,...r?.headers??{}},a=`${this.baseUrl.replace(/\/+$/,``)}/${this.canonicalPath(e)}`,o;try{o=await fetch(a,{method:`GET`,headers:i,signal:r?.signal})}catch(e){if(e instanceof Error&&e.name===`AbortError`){t.onClose?.();return}t.onError?.(e instanceof Error?e:Error(String(e)));return}if(o.status===401){this.onAuthStateChanged?.(),t.onError?.(new n({code:`AUTH-002-UNAUTH`,message:`Session expired`}));return}if(!o.ok||!o.body){t.onError?.(Error(`Stream request failed with status ${o.status}`));return}t.onOpen?.();let s=o.body.getReader(),c=new TextDecoder,l=``;try{for(;;){let{done:e,value:n}=await s.read();if(e)break;l+=c.decode(n,{stream:!0});let r=l.indexOf(`
2
2
 
3
3
  `);for(;r!==-1;){let e=l.slice(0,r);l=l.slice(r+2);let n=e.split(`
4
4
  `).filter(e=>e.startsWith(`data:`)).map(e=>e.slice(5).trim());n.length>0&&t.onMessage(n.join(`
5
5
  `)),r=l.indexOf(`
6
6
 
7
- `)}}}catch(e){e instanceof Error&&e.name===`AbortError`||t.onError?.(e instanceof Error?e:Error(String(e)))}finally{t.onClose?.()}}};const h={data:[],loading:!0,page:{number:1,size:20,count:0,total:0,pages:1}};function g(e,t,n,i){let o=n.page??1,s=n.size??20,c=n.sort,l=n.filter,u=new a({delay:50}),d=`${e}_pager_state_`;t.set({[d]:{data:[],loading:!1,error:r,page:{number:1,size:20,count:0,total:0,pages:1}}});let f=e=>{let t=e?.page??o,n=e?.size??s,r={pagination:{type:`offset`,offset:(t-1)*n,limit:n}},i=e?.sort??c;i&&(r.sort=Array.isArray(i)?i:[i]);let a=e?.filter??l;return a&&(r.filters=a),r},p=async e=>(await t.set({[d]:{loading:!0,error:r}}),await new Promise(n=>{n(u.do(async()=>{requestIdleCallback(()=>{requestIdleCallback(async()=>{try{let n=await i(f(e));await t.set({[d]:n})}catch(e){await t.set({[d]:{...h,error:e}})}finally{await t.set({[d]:{loading:!1}})}})})}))})),m=t.select(e=>e[d]),g=m.subscribe(()=>{});return{page:()=>m.get()??h,navigate:async e=>{if(e<1)throw Error(`Page number must be >= 1`);o=e,await p({page:e})},resize:async(e,t)=>{if(e<1)throw Error(`Page size must be >= 1`);s=e,o=t,await p()},sort:async e=>{c=Array.isArray(e)?e:[e],o=1,await p()},filter:async e=>{l=e,o=1,await p()},refresh:async e=>{await Promise.all([new Promise(t=>setTimeout(t,e?.delay||0)),p(e)])},subscribe:e=>m.subscribe(e),invalidate:async()=>{await t.set({[d]:r}),g()},id:()=>d}}var _=class{client;collectionName;defaultLimit;pagerOptions={};pager;constructor(e,t,n=50){this.client=e,this.collectionName=t,this.defaultLimit=n,this.pager=g(t,new i({}),this.pagerOptions,e=>this.find(e))}name(){return this.collectionName}get queryPath(){return`/system/collections/document/${encodeURIComponent(this.collectionName)}/query`}get documentsPath(){return`/system/collections/document/${encodeURIComponent(this.collectionName)}`}documentPath(e){return`${this.documentsPath}/${encodeURIComponent(e)}`}async find(e){let t=await this.client.post(this.queryPath,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async read(e){try{return(await this.client.get(this.documentPath(e))).data?.data}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){return(await this.client.post(this.documentsPath,e.data)).data.data}async update(e){let t=e.options;return(await this.client.patch(this.documentPath(t),e.data)).data.data}async delete(e){await this.client.delete(this.documentPath(e))}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:this.defaultLimit}})}async upload(e){throw Error(`Upload not supported for collections`)}async subscribe(e,t){throw Error(`Subscription not implemented for dynamic collections`)}async notify(e){throw Error(`Notify not implemented for dynamic collections`)}stream(e,t){throw Error(`Stream not supported for collections`)}page(e){return this.pager}},v=class{client;provider;constructor(e,t){this.client=e,this.provider=t}async health(){return(await this.client.get(`/system/core/health`)).data.data}async login(e,t){let n=(await this.client.post(`/system/auth/session`,{email:e,password:t})).data.data;return this.provider.setIdentity(n.user),n}async register(e,t,n){return(await this.client.post(`/system/auth/user`,{email:e,password:t,name:n})).data.data}async logout(){await this.client.delete(`/system/auth/session`),await this.provider.clear()}async requestPasswordReset(e){await this.client.post(`/system/auth/password`,{email:e})}async confirmPasswordReset(e,t){await this.client.patch(`/system/auth/password`,{password:t,token:e})}async bootstrap(e,t,n){await this.client.patch(`/system/auth/bootstrap`,{password:t,email:n},{headers:{"X-API-Key":e}})}},y=class{client;pagerOptions={};pager;constructor(e){this.client=e,this.pager=g(`users`,new i({}),this.pagerOptions,e=>this.find(e))}name(){return`users`}async find(e){let t=await this.client.post(`/system/users/user/query`,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1}}}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:50}})}async read(e){try{return(await this.client.get(`/system/users/user/${encodeURIComponent(e)}`)).data?.data}catch(e){if(e?.code===`SYNC-001-NF`)return;throw e}}async update(e){let t=e.options;return(await this.client.patch(`/system/users/user/${encodeURIComponent(t)}`,e.data)).data.data}async delete(e){await this.client.delete(`/system/users/user/${encodeURIComponent(e)}`)}async create(e){throw Error(`User creation requires email/password/name, use register endpoint`)}async upload(e){throw Error(`Upload not supported for users`)}async subscribe(e,t){throw Error(`Subscription not supported for users`)}async notify(e){throw Error(`Notify not supported for users`)}stream(e,t){throw Error(`Stream not supported for users`)}page(e){return this.pager}async changePassword(e,t,n){await this.client.patch(`/system/users/password/${encodeURIComponent(e)}`,{current:t,new:n})}},b=class{client;pager;constructor(e){this.client=e,this.pager=g(`_api_key_`,new i({}),{},e=>this.find(e))}basePath=`/system/apikeys/key`;async find(e){let t=await this.client.get(this.basePath),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1}}}async list(e){return e?this.find(e):this.find()}async read(e){try{return(await this.client.get(`${this.basePath}/${encodeURIComponent(e)}`)).data?.data}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`INTERNAL_ERROR`&&typeof e?.message==`string`&&e.message.includes(`not found`))return;throw e}}async create(e){return(await this.client.post(this.basePath,e.data)).data.data}async update(e){let t=e.options;return(await this.client.patch(`${this.basePath}/${encodeURIComponent(t)}`,e.data)).data.data}async delete(e){await this.client.delete(`${this.basePath}/${encodeURIComponent(e)}`)}async upload(e){throw Error(`Upload not supported for API keys`)}async subscribe(e,t){throw Error(`Subscription not supported for API keys`)}async notify(e){throw Error(`Notify not supported for API keys`)}stream(e,t){throw Error(`Stream not supported for API keys`)}page(e){return this.pager}async rotate(e){return(await this.client.post(`${this.basePath}/${encodeURIComponent(e)}`)).data.data}};const x=`/system/policies/operation`;var S=class{client;constructor(e){this.client=e}async list(){let e=(await this.client.get(x)).data?.data?.operations??[];return{data:e.map(e=>({data:e,metadata:{}})),loading:!1,page:{number:1,size:e.length,count:e.length,total:e.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${x}/${encodeURIComponent(e)}`);return t.data?.data?{data:t.data.data,metadata:{}}:void 0}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}};const C=`/system/policies/policy`;var w=class{client;pager;constructor(e){this.client=e,this.pager=g(`policies`,new i({}),{},e=>this.find(e))}async find(e){return this.query(e??{})}async query(e){let t=await this.client.post(`/system/collections/document/_operation_policy_/query`,e),n=t.data?.data??[],r=t.data?.metadata?.page;return{data:n.map(e=>({_id_:e._id_,_metadata_:e._metadata_,id:e._id_,operationName:e.operation??``,ruleName:e.rule??``,enabled:e.enabled??!0,protected:e.protected??!1})),loading:!1,page:r??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async list(e){let t=(await this.client.get(C)).data?.data?.policies??[];return{data:t.map(e=>({data:e,metadata:{}})),loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${C}/${encodeURIComponent(e)}`);return t.data?.data?{data:t.data.data,metadata:{}}:void 0}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){let t=e.options??e.data.name;if(!t)throw Error(`Operation name is required for create`);let n={ruleName:e.data.ruleName??``},r=await this.client.post(`${C}/${encodeURIComponent(t)}`,n);if(r.data?.data)return{data:r.data.data,metadata:{}}}async update(e){let t=e.options;if(!t)throw Error(`Operation name is required for update`);let n=await this.client.patch(`${C}/${encodeURIComponent(t)}`,e.data);if(n.data?.data)return{data:n.data.data,metadata:{}}}async setEnabled(e,t){return{data:(await this.client.patch(`${C}/${encodeURIComponent(e)}`,{enabled:t})).data.data,metadata:{}}}async delete(e){throw Error(`Policies cannot be deleted; disable instead`)}async upload(e){throw Error(`Upload not supported for policies`)}async subscribe(e,t){throw Error(`Subscription not supported for policies`)}async notify(e){throw Error(`Notify not supported for policies`)}stream(e,t){throw Error(`Stream not supported for policies`)}page(e){return this.pager}};const T=`/system/policies/rule`;var E=class{client;constructor(e){this.client=e}async find(e){return this.list()}async list(e){let t=(await this.client.get(T)).data?.data?.rules??[];return{data:t.map(e=>({_id_:e.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...e})),loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${T}/${encodeURIComponent(e)}`);if(!t.data?.data)return;let n=t.data.data;return{_id_:n.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...n}}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){let t=e.options;if(!t)throw Error(`Rule name is required for create`);let n=await this.client.post(`${T}/${encodeURIComponent(t)}`,e.data);if(!n.data?.data)return;let r=n.data.data;return{_id_:r.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...r}}async update(e){let t=e.options;if(!t)throw Error(`Rule name is required for update`);let n=await this.client.patch(`${T}/${encodeURIComponent(t)}`,e.data);if(!n.data?.data)return;let r=n.data.data;return{_id_:r.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...r}}async delete(e){await this.client.delete(`${T}/${encodeURIComponent(e)}`)}async validate(e){return(await this.client.post(`${T}/query`,{expression:e})).data?.data?.valid??!1}async reload(){return(await this.client.get(T)).data.data}async upload(e){throw Error(`Upload not supported for rules`)}async subscribe(e,t){throw Error(`Subscription not supported for rules`)}async notify(e){throw Error(`Notify not supported for rules`)}stream(e,t){throw Error(`Stream not supported for rules`)}page(e){throw Error(`Pagination not supported for rules`)}},D=class{client;baseUrl;pagerOptions={};pager;apiPrefix;constructor(e,t,n=`/api`){this.client=e,this.baseUrl=t,this.apiPrefix=n,this.pager=g(`_audit_log_`,new i({}),this.pagerOptions,e=>this.find(e))}async find(e){let t=await this.client.post(`/system/audit/log/query`,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:50}})}async read(e){throw Error(`Read by ID not supported for audit logs; use find with filters`)}async create(e){throw Error(`Audit logs are write-only; entries are created by the system`)}async update(e){throw Error(`Audit logs are append-only; updates are not allowed`)}async delete(e){throw Error(`Audit logs are append-only; deletion is not allowed`)}async upload(e){throw Error(`Upload not supported for audit logs`)}async subscribe(e,t){throw Error(`Use stream() for real-time audit log entries`)}async notify(e){throw Error(`Notify not supported for audit logs`)}stream(e,t){let n=this.getStreamUrl(),r=null,i=`active`,a=null,o=async function*(){let e=[];r=new EventSource(n,{withCredentials:!0}),r.onmessage=t=>{for(let n of t.data.split(`
7
+ `)}}}catch(e){e instanceof Error&&e.name===`AbortError`||t.onError?.(e instanceof Error?e:Error(String(e)))}finally{t.onClose?.()}}};const h={data:[],loading:!0,page:{number:1,size:20,count:0,total:0,pages:1}};function g(e,t,n,i){let o=n.page??1,s=n.size??20,c=n.sort,l=n.filter,u=new a({delay:50}),d=`${e}_pager_state_`;t.set({[d]:{data:[],loading:!1,error:r,page:{number:1,size:20,count:0,total:0,pages:1}}});let f=e=>{let t=e?.page??o,n=e?.size??s,r={pagination:{type:`offset`,offset:(t-1)*n,limit:n}},i=e?.sort??c;i&&(r.sort=Array.isArray(i)?i:[i]);let a=e?.filter??l;return a&&(r.filters=a),r},p=async e=>(await t.set({[d]:{loading:!0,error:r}}),await new Promise(n=>{n(u.do(async()=>{requestIdleCallback(()=>{requestIdleCallback(async()=>{try{let n=await i(f(e));await t.set({[d]:n})}catch(e){await t.set({[d]:{...h,error:e}})}finally{await t.set({[d]:{loading:!1}})}})})}))})),m=t.select(e=>e[d]),g=m.subscribe(()=>{});return{page:()=>m.get()??h,navigate:async e=>{if(e<1)throw Error(`Page number must be >= 1`);o=e,await p({page:e})},resize:async(e,t)=>{if(e<1)throw Error(`Page size must be >= 1`);s=e,o=t,await p()},sort:async e=>{c=Array.isArray(e)?e:[e],o=1,await p()},filter:async e=>{l=e,o=1,await p()},refresh:async e=>{await Promise.all([new Promise(t=>setTimeout(t,e?.delay||0)),p(e)])},subscribe:e=>m.subscribe(e),invalidate:async()=>{await t.set({[d]:r}),g()},id:()=>d}}var _=class{client;collectionName;defaultLimit;pagerOptions={};pager;constructor(e,t,n=50){this.client=e,this.collectionName=t,this.defaultLimit=n,this.pager=g(t,new i({}),this.pagerOptions,e=>this.find(e))}name(){return this.collectionName}get queryPath(){return`/system/collections/document/${encodeURIComponent(this.collectionName)}/query`}get documentsPath(){return`/system/collections/document/${encodeURIComponent(this.collectionName)}`}documentPath(e){return`${this.documentsPath}/${encodeURIComponent(e)}`}async find(e){let t=await this.client.post(this.queryPath,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async read(e){try{return(await this.client.get(this.documentPath(e))).data?.data}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){return(await this.client.post(this.documentsPath,e.data)).data.data}async update(e){let t=e.options;return(await this.client.patch(this.documentPath(t),e.data)).data.data}async delete(e){await this.client.delete(this.documentPath(e))}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:this.defaultLimit}})}async upload(e){throw Error(`Upload not supported for collections`)}async subscribe(e,t){throw Error(`Subscription not implemented for dynamic collections`)}async notify(e){throw Error(`Notify not implemented for dynamic collections`)}stream(e,t){throw Error(`Stream not supported for collections`)}page(e){return this.pager}},v=class{client;provider;constructor(e,t){this.client=e,this.provider=t}async health(){return(await this.client.get(`/system/core/health`)).data.data}async login(e,t){let n=(await this.client.post(`/system/auth/session`,{email:e,password:t})).data.data;return this.provider.setIdentity(n.user),n}async register(e,t,n){return(await this.client.post(`/system/auth/user`,{email:e,password:t,name:n})).data.data}async logout(){await this.client.delete(`/system/auth/session`),await this.provider.clear()}async requestPasswordReset(e){await this.client.post(`/system/auth/password`,{email:e})}async confirmPasswordReset(e,t){await this.client.patch(`/system/auth/password`,{password:t,token:e})}async bootstrap(e,t,n){await this.client.patch(`/system/auth/bootstrap`,{password:t,email:n},{headers:{"X-API-Key":e}})}},y=class{client;pagerOptions={};pager;constructor(e){this.client=e,this.pager=g(`users`,new i({}),this.pagerOptions,e=>this.find(e))}name(){return`users`}async find(e){let t=await this.client.post(`/system/users/user/query`,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1}}}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:50}})}async read(e){try{return(await this.client.get(`/system/users/user/${encodeURIComponent(e)}`)).data?.data}catch(e){if(e?.code===`SYNC-001-NF`)return;throw e}}async update(e){let t=e.options;return(await this.client.patch(`/system/users/user/${encodeURIComponent(t)}`,e.data)).data.data}async delete(e){await this.client.delete(`/system/users/user/${encodeURIComponent(e)}`)}async create(e){throw Error(`User creation requires email/password/name, use register endpoint`)}async upload(e){throw Error(`Upload not supported for users`)}async subscribe(e,t){throw Error(`Subscription not supported for users`)}async notify(e){throw Error(`Notify not supported for users`)}stream(e,t){throw Error(`Stream not supported for users`)}page(e){return this.pager}async changePassword(e,t,n){await this.client.patch(`/system/users/password/${encodeURIComponent(e)}`,{current:t,new:n})}},b=class{client;pager;constructor(e){this.client=e,this.pager=g(`_api_key_`,new i({}),{},e=>this.find(e))}basePath=`/system/apikeys/key`;async find(e){let t=await this.client.get(this.basePath),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1}}}async list(e){return e?this.find(e):this.find()}async read(e){try{return(await this.client.get(`${this.basePath}/${encodeURIComponent(e)}`)).data?.data}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`INTERNAL_ERROR`&&typeof e?.message==`string`&&e.message.includes(`not found`))return;throw e}}async create(e){return(await this.client.post(this.basePath,e.data)).data.data}async update(e){let t=e.options;return(await this.client.patch(`${this.basePath}/${encodeURIComponent(t)}`,e.data)).data.data}async delete(e){await this.client.delete(`${this.basePath}/${encodeURIComponent(e)}`)}async upload(e){throw Error(`Upload not supported for API keys`)}async subscribe(e,t){throw Error(`Subscription not supported for API keys`)}async notify(e){throw Error(`Notify not supported for API keys`)}stream(e,t){throw Error(`Stream not supported for API keys`)}page(e){return this.pager}async rotate(e){return(await this.client.post(`${this.basePath}/${encodeURIComponent(e)}`)).data.data}};const x=`/system/policies/operation`;var S=class{client;constructor(e){this.client=e}async list(){let e=(await this.client.get(x)).data?.data?.operations??[];return{data:e.map(e=>({data:e,metadata:{}})),loading:!1,page:{number:1,size:e.length,count:e.length,total:e.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${x}/${encodeURIComponent(e)}`);return t.data?.data?{data:t.data.data,metadata:{}}:void 0}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}};const C=`/system/policies/policy`;var w=class{client;pager;constructor(e){this.client=e,this.pager=g(`policies`,new i({}),{},e=>this.find(e))}async find(e){return this.query(e??{})}async query(e){let t=await this.client.post(`/system/collections/document/_operation_policy_/query`,e),n=t.data?.data??[],r=t.data?.metadata?.page;return{data:n.map(e=>({_id_:e._id_,_metadata_:e._metadata_,id:e._id_,operationName:e.operation??``,ruleName:e.rule??``,enabled:e.enabled??!0,protected:e.protected??!1})),loading:!1,page:r??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async list(e){let t=(await this.client.get(C)).data?.data?.policies??[];return{data:t.map(e=>({data:e,metadata:{}})),loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${C}/${encodeURIComponent(e)}`);return t.data?.data?{data:t.data.data,metadata:{}}:void 0}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){let t=e.options??e.data.name;if(!t)throw Error(`Operation name is required for create`);let n={ruleName:e.data.ruleName??``},r=await this.client.post(`${C}/${encodeURIComponent(t)}`,n);if(r.data?.data)return{data:r.data.data,metadata:{}}}async update(e){let t=e.options;if(!t)throw Error(`Operation name is required for update`);let n=await this.client.patch(`${C}/${encodeURIComponent(t)}`,e.data);if(n.data?.data)return{data:n.data.data,metadata:{}}}async setEnabled(e,t){return{data:(await this.client.patch(`${C}/${encodeURIComponent(e)}`,{enabled:t})).data.data,metadata:{}}}async delete(e){throw Error(`Policies cannot be deleted; disable instead`)}async upload(e){throw Error(`Upload not supported for policies`)}async subscribe(e,t){throw Error(`Subscription not supported for policies`)}async notify(e){throw Error(`Notify not supported for policies`)}stream(e,t){throw Error(`Stream not supported for policies`)}page(e){return this.pager}};const T=`/system/policies/rule`;var E=class{client;constructor(e){this.client=e}async find(e){return this.list()}async list(e){let t=(await this.client.get(T)).data?.data?.rules??[];return{data:t.map(e=>({_id_:e.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...e})),loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1},error:null}}async read(e){try{let t=await this.client.get(`${T}/${encodeURIComponent(e)}`);if(!t.data?.data)return;let n=t.data.data;return{_id_:n.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...n}}catch(e){if(e?.code===`SYNC-001-NF`||e?.code===`NOT_FOUND`)return;throw e}}async create(e){let t=e.options??e.data.name;if(!t)throw Error(`Rule name is required for create`);let n=await this.client.post(`${T}/${encodeURIComponent(t)}`,e.data);if(!n.data?.data)return;let r=n.data.data;return{_id_:r.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...r}}async update(e){let t=e.options;if(!t)throw Error(`Rule name is required for update`);let n=await this.client.patch(`${T}/${encodeURIComponent(t)}`,e.data);if(!n.data?.data)return;let r=n.data.data;return{_id_:r.id,_metadata_:{checksum:``,created:``,updated:``,version:1},...r}}async delete(e){await this.client.delete(`${T}/${encodeURIComponent(e)}`)}async validate(e){return(await this.client.check(T,e)).data?.data??{valid:!1}}async reload(){return(await this.client.get(T)).data.data}async upload(e){throw Error(`Upload not supported for rules`)}async subscribe(e,t){throw Error(`Subscription not supported for rules`)}async notify(e){throw Error(`Notify not supported for rules`)}stream(e,t){throw Error(`Stream not supported for rules`)}page(e){throw Error(`Pagination not supported for rules`)}},D=class{client;baseUrl;pagerOptions={};pager;apiPrefix;constructor(e,t,n=`/api`){this.client=e,this.baseUrl=t,this.apiPrefix=n,this.pager=g(`_audit_log_`,new i({}),this.pagerOptions,e=>this.find(e))}async find(e){let t=await this.client.post(`/system/audit/log/query`,e??{}),n=t.data?.data??[];return{data:n,loading:!1,page:t.data?.metadata?.page??{number:1,size:n.length,count:n.length,total:n.length,pages:1},error:null}}async list(e){return this.find(e??{pagination:{type:`offset`,offset:0,limit:50}})}async read(e){throw Error(`Read by ID not supported for audit logs; use find with filters`)}async create(e){throw Error(`Audit logs are write-only; entries are created by the system`)}async update(e){throw Error(`Audit logs are append-only; updates are not allowed`)}async delete(e){throw Error(`Audit logs are append-only; deletion is not allowed`)}async upload(e){throw Error(`Upload not supported for audit logs`)}async subscribe(e,t){throw Error(`Use stream() for real-time audit log entries`)}async notify(e){throw Error(`Notify not supported for audit logs`)}stream(e,t){let n=this.getStreamUrl(),r=null,i=`active`,a=null,o=async function*(){let e=[];r=new EventSource(n,{withCredentials:!0}),r.onmessage=t=>{for(let n of t.data.split(`
8
8
  `)){let t=n.trim();if(t)try{let n=JSON.parse(t);n?.data&&e.push(n.data)}catch{}}e.length>0&&a&&(a(),a=null)},r.onerror=()=>{i===`active`&&(i=`completed`),a&&=(a(),null)};try{for(;i===`active`;)e.length>0?yield e.shift():await new Promise(t=>{a=t,e.length>0&&(t(),a=null)})}finally{r?.close(),a&&=(a(),null),i===`active`&&(i=`completed`)}};return{stream:()=>o(),cancel:()=>{i===`active`&&(i=`cancelled`,r?.close())},status:()=>i}}page(e){return this.pager}getStreamUrl(){return`${this.baseUrl}${this.apiPrefix}/system/audit/log/stream`}};function O(e){return{_id_:e.key,_metadata_:{checksum:``,created:e.created_at,updated:e.updated_at??e.created_at,version:1},...e}}function k(e){return{number:1,size:e.length,count:e.length,total:e.length,pages:1}}var A=class{client;ns;pagerOptions={};pager;prefixFilter=``;constructor(e,t){this.client=e,this.ns=t,this.pager=g(`blobs_${t}`,new i({}),this.pagerOptions,e=>this.find(e))}name(){return this.ns}setPrefix(e){this.prefixFilter=e}basePath(){return`/system/blobs/blob/${encodeURIComponent(this.ns)}`}async find(e){let t=this.prefixFilter||e?.prefix||``,n=e?.limit??e?.pagination?.limit??0,r={};t&&(r.prefix=t),n&&(r.limit=n);let i=(await this.client.post(`${this.basePath()}/query`,r)).data?.data?.blobs??[];return{data:i.map(O),loading:!1,page:k(i),error:void 0}}async read(e){try{let t=await this.client.post(`${this.basePath()}/${encodeURIComponent(e)}/query`);return t.data?.data?O(t.data.data):void 0}catch(e){if(e?.code===`NOT_FOUND`)return;throw e}}async create(e){throw Error(`Use upload() to create blobs`)}async update(e){let t=e.options?.key;if(!t)throw Error(`options.key is required for blob update`);return O((await this.client.patch(`${this.basePath()}/${encodeURIComponent(t)}`,{custom:e.data})).data.data)}async delete(e){await this.client.delete(`${this.basePath()}/${encodeURIComponent(e)}`)}async list(e){return this.find(e??{})}async upload(e){let t=e.options?.key;if(!t)throw Error(`options.key is required for blob upload`);let n={},r=e.options?.contentType||e.file.type;return r&&(n[`Content-Type`]=r),O((await this.client.post(`${this.basePath()}/${encodeURIComponent(t)}`,e.file,{headers:n,bodyType:`blob`})).data.data)}async subscribe(e,t){throw Error(`Subscription not supported for blobs`)}async notify(e){throw Error(`Notify not supported for blobs`)}stream(e,t){throw Error(`Stream not supported for blobs`)}page(e){return this.pager}async download(e){let t=(await this.client.get(`${this.basePath()}/${encodeURIComponent(e)}`,{responseType:`blob`})).data;return{data:t,contentType:t.type}}},j=class{client;apiPrefix;constructor(e,t=`/api`){this.client=e,this.apiPrefix=t}nsBase=`/system/blobs`;async namespaces(){return(await this.client.post(`${this.nsBase}/namespace/query`)).data?.data?.namespaces??[]}async createNamespace(e){return(await this.client.post(`${this.nsBase}/namespace`,e)).data.data}async deleteNamespace(e){await this.client.delete(`${this.nsBase}/namespace/${encodeURIComponent(e)}`)}blob(e,t){return`${this.client.base()}${this.apiPrefix}${this.nsBase}/blob/${encodeURIComponent(e)}/${encodeURIComponent(t)}`}namespace(e){return new A(this.client,e)}},M=class{client;constructor(e){this.client=e}async find(e){let t=((await this.client.get(`/system/collections/collection`)).data?.data??[]).map(e=>({_id_:e.name,_metadata_:{checksum:``,created:e.created,updated:e.updated,version:1},name:e.name,schema:e.schema,created:e.created,updated:e.updated}));return{data:t,loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1}}}async read(e){try{let t=await this.client.get(`/system/collections/collection/${encodeURIComponent(e)}`);if(!t.data)return;let n=t.data.data;return{_id_:n.name,_metadata_:{checksum:``,created:n.created,updated:n.updated,version:1},name:n.name,schema:n.schema,created:n.created,updated:n.updated}}catch(e){if(e?.code===`SYNC-001-NF`)return;throw e}}async create(e){return(await this.client.post(`/system/collections/collection`,e.data)).data.data}async update(e){throw Error(`Collection update not implemented`)}async delete(e){await this.client.delete(`/system/collections/collection/${encodeURIComponent(e)}`)}async list(e){return this.find()}async upload(e){throw Error(`Upload not supported for collections`)}async subscribe(e,t){throw Error(`Subscription not supported for collections`)}async notify(e){throw Error(`Notify not supported for collections`)}stream(e,t){throw Error(`Stream not supported for collections`)}page(e){throw Error(`Pagination not supported for collection metadata; use documents(name)`)}documents(e){return new _(this.client,e)}},N=class{client;constructor(e){this.client=e}async find(e){let t=(await this.client.get(`/system/core/docs`)).data?.data??[];return{data:t,loading:!1,page:{number:1,size:t.length,count:t.length,total:t.length,pages:1}}}async read(e){throw Error(`Read by ID not supported for capabilities; use find()`)}async create(e){throw Error(`Capabilities are read-only`)}async update(e){throw Error(`Capabilities are read-only`)}async delete(e){throw Error(`Capabilities are read-only`)}async list(e){return this.find()}async upload(e){throw Error(`Upload not supported for capabilities`)}async subscribe(e,t){throw Error(`Subscription not supported for capabilities`)}async notify(e){throw Error(`Notify not supported for capabilities`)}stream(e,t){throw Error(`Stream not supported for capabilities`)}page(e){throw Error(`Pagination not supported for capabilities`)}},P=class{store;client;auth;users;keys;policies;rules;logs;collections;blobs;capabilities;tokenProvider;onAuthStateChanged;constructor(e){this.store=new i({identity:null},e.persistence);let t={identity:()=>this.store.get().identity,setIdentity:async e=>void await this.store.set({identity:e}),clear:async()=>void await this.store.set({identity:null})},n=e.apiPrefix??`/api`;this.tokenProvider=t,this.client=new m(e.baseUrl,n,t,()=>this.onAuthStateChanged?.()),this.auth=new v(this.client,t),this.users=new y(this.client),this.keys=new b(this.client),this.policies=new w(this.client),this.rules=new E(this.client),this.logs=new D(this.client,e.baseUrl,n),this.collections=new M(this.client),this.blobs=new j(this.client,n),this.capabilities=new N(this.client)}onAuthStateChange(e){this.onAuthStateChanged=e}authenticated(){return this.tokenProvider.identity()!==null}collection(e){return this.collections.documents(e)}};function F(e){let t=`${e.collectionName}_array_pager_state_`,n=new i({}),a=[...e.initialData??[]],c=`collection`,l,u=e.page??1,d=e.size??20,f=[],p,m,{match:h}=o(e.customFunctions??{}),{sort:g}=s(),_=n.select(e=>e[t]),v={data:[],loading:!0,error:void 0,page:{number:1,size:d,count:0,total:0,pages:1}},y=()=>({filters:p,sort:f,pagination:{type:`offset`,offset:(u-1)*d,limit:d}}),b=async(r=!0)=>{if(e.fetch){if(m=void 0,r){let e=_.get()??v;await n.set({[t]:{...e,loading:!0,error:void 0}})}try{let t=y(),n=await e.fetch(t);c=n.scope,l=n.total,a=n.replace?[...n.data]:[...a,...n.data]}catch(e){m=e}}let i=x(e.fetch?r:!1);await n.set({[t]:i})},x=e=>{let t=[...a];if(c===`collection`){p&&(t=t.filter(e=>h(e,p))),f.length>0&&(t=g(t,f));let n=t.length,r=Math.ceil(n/d)||1;u>r&&(u=r),u<1&&(u=1);let i=(u-1)*d,a=t.slice(i,i+d);return{data:a,loading:e,error:m,page:{number:u,size:d,count:a.length,total:n,pages:r}}}let n=l??t.length,r=Math.ceil(n/d)||1;return{data:t,loading:e,error:m,page:{number:u,size:d,count:t.length,total:n,pages:r}}};return b(!0),{id:()=>t,page:()=>_.get()??v,navigate:async e=>{if(e<1)throw Error(`Page number must be >= 1`);u=e,await b(!0)},resize:async(e,t)=>{if(e<1)throw Error(`Page size must be >= 1`);d=e,u=t,await b(!0)},sort:async e=>{f=Array.isArray(e)?e:[e],u=1,await b(!0)},filter:async e=>{p=e,u=1,await b(!0)},refresh:async e=>{let r=_.get()??v;await n.set({[t]:{...r,loading:!0}});let i=e?.delay??600;await Promise.all([new Promise(e=>setTimeout(e,i)),b(!1)]);let a=_.get()??v;await n.set({[t]:{...a,loading:!1}})},subscribe:e=>_.subscribe(t=>{e(t)}),invalidate:async()=>{await n.set({[t]:r}),a=[]}}}export{A as BlobNamespace,v as HestiaAuth,j as HestiaBlobClient,P as HestiaClient,_ as HestiaCollection,M as HestiaCollections,b as HestiaKeyStore,D as HestiaLogs,m as HestiaNetworkClient,S as HestiaOperations,w as HestiaPolicies,p as HestiaResponse,E as HestiaRules,y as HestiaUsers,F as createArrayPager,g as createPagedController,f as internalError,u as notFound,c as parseErrorBody,d as permissionDenied,l as toSystemError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asaidimu/hestia",
3
- "version": "1.0.6",
3
+ "version": "1.1.0",
4
4
  "description": "TypeScript client SDK for the Hestia platform — auth, collections, API keys, policies, audit logs, blobs, and capabilities",
5
5
  "type": "module",
6
6
  "main": "./index.cjs",