genosdb 0.14.1 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # GenosDB (GDB) – Decentralized P2P Graph Database
2
2
 
3
- A lightweight, decentralized graph database designed for modern web applications, offering real-time peer-to-peer synchronization, SM ([Security Manager](https://github.com/estebanrfp/gdb/blob/main/docs/sm-architecture.md)) Provides WebAuthn-based authentication, role-based access control (RBAC), Access Control Lists ([ACLs](https://github.com/estebanrfp/gdb/blob/main/docs/sm-acls-module.md)), rule-based role promotion ([Governance](https://github.com/estebanrfp/gdb/blob/main/docs/governance.md)), and efficient local storage utilizing OPFS.
3
+ A lightweight, decentralized graph database designed for modern web applications, offering real-time peer-to-peer synchronization, SM ([Security Manager](https://github.com/estebanrfp/gdb/blob/main/docs/sm-architecture.md)) Provides WebAuthn-based authentication, role-based access control (RBAC), Access Control Lists ([ACLs](https://github.com/estebanrfp/gdb/blob/main/docs/sm-acls-module.md)), rule-based role promotion & demotion ([Governance](https://github.com/estebanrfp/gdb/blob/main/docs/governance.md)), and efficient local storage utilizing OPFS.
4
4
 
5
5
  ![GenosDB](https://i.imgur.com/7Xqrht1.png)
6
6
 
@@ -27,6 +27,7 @@ A lightweight, decentralized graph database designed for modern web applications
27
27
  ![Nostr.band Followers](https://img.shields.io/nostr-band/followers/npub18c556t7n8xa3df2q82rwxejfglw5przds7sqvefylzjh8tjne28qld0we7) -->
28
28
 
29
29
  ## Table of Contents
30
+ - [How it works](#how-it-works)
30
31
  - [Main Features](#main-features)
31
32
  - [Project Status](#project-status)
32
33
  - [Installation](#installation)
@@ -36,6 +37,21 @@ A lightweight, decentralized graph database designed for modern web applications
36
37
  - [Business Inquiries Collaboration](#business-inquiries--collaboration)
37
38
 
38
39
 
40
+ ## How it works
41
+
42
+ GenosDB runs **entirely in your browser** — there is no central database server. The Security Manager signs every operation with your key, nodes are stored locally in OPFS, and changes replicate **peer-to-peer over WebRTC**. Nostr relays only help peers discover each other — they never see your data.
43
+
44
+ ```mermaid
45
+ %%{init: {'theme':'base', 'themeVariables': {'primaryColor':'transparent','primaryBorderColor':'#3b82f6','primaryTextColor':'#64748b','lineColor':'#3b82f6','edgeLabelBackground':'#22222200','fontFamily':'Inter, ui-sans-serif, sans-serif'}}}%%
46
+ graph TD
47
+ A["Your Browser + GenosDB"] -->|signs every action| B["Security Manager — your key"]
48
+ A -->|stores nodes| C["Graph store · OPFS"]
49
+ A -->|reactive queries| D["db.map subscriptions"]
50
+ C -->|P2P delta sync over WebRTC| E["Other Participants"]
51
+ C -->|cross-tab| F["BroadcastChannel"]
52
+ G["Nostr relays"] -.->|signaling / peer discovery only| A
53
+ ```
54
+
39
55
  ## Main Features
40
56
 
41
57
  ### ✅ **GenosDB Core**
@@ -64,7 +80,7 @@ A lightweight, decentralized graph database designed for modern web applications
64
80
  - **Intelligent Hybrid Synchronization:**
65
81
  GenosDB overcomes the limitations of naive P2P sync with an intelligent, dual-mode engine. It automatically exchanges tiny, compressed Deltas between active peers using a sliding-window Oplog for blazing-fast, low-latency updates. For peers that are too far out of sync, it seamlessly switches to a robust Full-State Fallback, guaranteeing absolute data consistency for everyone, no matter how long they've been offline.
66
82
  - **Access Control Lists (ACLs):** Optional submodule for fine-grained, node-level permissions, allowing owners to grant/revoke specific permissions ('read', 'write', 'delete') to other users per node, complementing the existing RBAC system.
67
- - **Governance (Role Promotion):** Optional engine that promotes users between roles from declarative rules whose conditions are native GenosDB queries, with each promotion signed by an online superadmin. ([Governance](https://github.com/estebanrfp/gdb/blob/main/docs/governance.md))
83
+ - **Governance (Role Promotion & Demotion):** Optional engine that resolves each user's role from declarative rules (native GenosDB queries) using **last-match-wins** — a merit ladder where climbing overrides lower tiers and losing the condition auto-demotes, each change signed by an online superadmin. ([Governance](https://github.com/estebanrfp/gdb/blob/main/docs/governance.md))
68
84
 
69
85
  ### 🧪 API Status: Stable Beta
70
86
 
package/dist/geo.min.js CHANGED
@@ -1 +1 @@
1
- function Q(F){let K={$near:(b,H)=>{let{latitude:k,longitude:A,radius:f}=H;if(typeof k!=="number"||typeof A!=="number"||typeof f!=="number")return!1;let E=b?.latitude||b?.location?.latitude,j=b?.longitude||b?.location?.longitude;if(typeof E!=="number"||typeof j!=="number")return!1;return N(E,j,k,A)<=f},$bbox:(b,H)=>{let{minLat:k,maxLat:A,minLng:f,maxLng:E}=H;if(typeof k!=="number"||typeof A!=="number"||typeof f!=="number"||typeof E!=="number")return!1;let j=b?.latitude||b?.location?.latitude,C=b?.longitude||b?.location?.longitude;if(typeof j!=="number"||typeof C!=="number")return!1;return j>=k&&j<=A&&C>=f&&C<=E}};function N(b,H,k,A){let f=(P)=>P*Math.PI/180,E=6371,j=f(k-b),C=f(A-H),J=Math.sin(j/2)*Math.sin(j/2)+Math.cos(f(b))*Math.cos(f(k))*Math.sin(C/2)*Math.sin(C/2);return 6371*(2*Math.atan2(Math.sqrt(J),Math.sqrt(1-J)))}return F.operators={...F.operators,...K},F}var T=(F)=>{return Q(F)};export{Q as withModule,T as init};
1
+ function $(U){let O={$near:(z,J)=>{let{latitude:A,longitude:E,radius:I}=J;if(typeof A!=="number"||typeof E!=="number"||typeof I!=="number")return!1;let S=z?.latitude||z?.location?.latitude,F=z?.longitude||z?.location?.longitude;if(typeof S!=="number"||typeof F!=="number")return!1;return q(S,F,A,E)<=I},$bbox:(z,J)=>{let{minLat:A,maxLat:E,minLng:I,maxLng:S}=J;if(typeof A!=="number"||typeof E!=="number"||typeof I!=="number"||typeof S!=="number")return!1;let F=z?.latitude||z?.location?.latitude,H=z?.longitude||z?.location?.longitude;if(typeof F!=="number"||typeof H!=="number")return!1;return F>=A&&F<=E&&H>=I&&H<=S}};function q(z,J,A,E){let I=(W)=>W*Math.PI/180,S=6371,F=I(A-z),H=I(E-J),T=Math.sin(F/2)*Math.sin(F/2)+Math.cos(I(z))*Math.cos(I(A))*Math.sin(H/2)*Math.sin(H/2);return 6371*(2*Math.atan2(Math.sqrt(T),Math.sqrt(1-T)))}U.operators={...U.operators,...O};let k=(z)=>{let J=[];if(!z||typeof z!=="object")return{geoConditions:J,restQuery:z};let A={};for(let[E,I]of Object.entries(z)){if(E==="$near"||E==="$bbox"){J.push({op:E,params:I});continue}if(I&&typeof I==="object"&&!Array.isArray(I)){let S={},F=!1;for(let[H,T]of Object.entries(I))if(H==="$near"||H==="$bbox")J.push({op:H,params:T}),F=!0;else S[H]=T;if(F){if(Object.keys(S).length)A[E]=S;continue}}A[E]=I}return{geoConditions:J,restQuery:A}},j=(z,J)=>z!=null&&J.every(({op:A,params:E})=>O[A](z,E)),Q=(z,J)=>J.split(".").reduce((A,E)=>A&&typeof A==="object"&&(E in A)?A[E]:void 0,z),R=(z,{field:J,order:A,$after:E,$before:I,$limit:S})=>{let F=[...z];if(J){let H=A==="asc"?1:-1;F.sort((T,_)=>{let W=Q(T.value,J),Y=Q(_.value,J);if(typeof W==="string"&&typeof Y==="string")return W.localeCompare(Y)*H;return((W??0)-(Y??0))*H})}if(E){let H=F.findIndex((T)=>T.id===E);F=H>=0?F.slice(H+1):[]}if(I){let H=F.findIndex((T)=>T.id===I);F=H>=0?F.slice(0,H):[]}if(S)F=F.slice(0,S);return F},N=U.map;return U.map=async(...z)=>{let J=z.find((K)=>K&&typeof K==="object")??{},A=z.find((K)=>typeof K==="function"),{geoConditions:E,restQuery:I}=k(J.query);if(!E.length)return N(...z);let{query:S,field:F,order:H,$limit:T,$after:_,$before:W,...Y}=J,x={...Y,query:I},M={field:F,order:H,$limit:T,$after:_,$before:W};if(!A){let{results:K=[]}=await N(x);return{results:R(K.filter((X)=>j(X.value,E)),M)}}let Z=new Set,B=await N(x,(K)=>{let{id:X,value:G,action:D}=K;if(D==="removed"){if(Z.delete(X))A(K);return}let P=j(G,E),w=Z.has(X);if(P&&!w)Z.add(X),A(D==="updated"?{...K,action:"added"}:K);else if(P&&w)A(K);else if(!P&&w)Z.delete(X),A({...K,value:null,action:"removed"})}),C=R((B.results??[]).filter((K)=>j(K.value,E)),M);return C.forEach((K)=>Z.add(K.id)),{...B,results:C}},U}var b=(U)=>{return $(U)};export{$ as withModule,b as init};
Binary file
@@ -1 +1 @@
1
- var H=null,K=[],M=[],F=null,L=(f)=>!!f&&M.some((q)=>q&&q.toLowerCase()===f.toLowerCase()),P=async()=>{let f=Date.now();try{let{results:q=[]}=await H.map({query:{role:{$exists:!0}}});for(let j of q){if(!j.id.startsWith("user:"))continue;let B=j.id.slice(5);if(L(B))continue;let z=j.value?.expiresAt;if(!z||new Date(z).getTime()>f)continue;let D=K.find((J)=>J.then?.expiresTo&&J.then?.assignRole===j.value.role);if(!D||j.value.role===D.then.expiresTo)continue;await H.sm.assignRole(B,D.then.expiresTo,null)}}catch(q){}},Q=async()=>{await P();for(let f of K)try{let{results:q=[]}=await H.map({query:f.if});for(let j of q){if(!j.id.startsWith("user:"))continue;let B=j.id.slice(5);if(L(B))continue;if(f.offsetTimestamp&&(j.timestamp?.physical??0)>Date.now()-f.offsetTimestamp)continue;let{assignRole:z,expiresIn:D,expiresAt:J}=f.then??{};if(!z||j.value?.role===z)continue;let N=J??(D!=null?Date.now()+D:null);await H.sm.assignRole(B,z,N)}}catch(q){}},U=()=>{if(F)return;F=setInterval(Q,4000)},V=()=>{if(!F)return;clearInterval(F),F=null},W=(f,{governanceRules:q,superAdmins:j}={})=>{if(!f||!q)return;H=f,K=q,M=j||[],f.sm.setGovernanceStateChangeCallback(({isActive:B,activeAddress:z})=>{if(B&&z&&L(z))U();else V()})};export{W as start};
1
+ var D=null,F=[],H=[],B=null,J=(q)=>!!q&&H.some((f)=>f&&f.toLowerCase()===q.toLowerCase()),K=async()=>{let q=new Map;for(let f of F){let x=f.then?.assignRole;if(!x)continue;let z=[];try{({results:z=[]}=await D.map({query:f.if}))}catch(j){continue}for(let j of z){if(!j.id.startsWith("user:"))continue;if(J(j.id.slice(5)))continue;if(f.offsetTimestamp&&(j.timestamp?.physical??0)>Date.now()-f.offsetTimestamp)continue;q.set(j.id,{role:x,current:j.value?.role})}}for(let[f,{role:x,current:z}]of q){if(z===x)continue;let j=f.slice(5);try{await D.sm.assignRole(j,x)}catch(N){}}},L=()=>{if(B)return;B=setInterval(K,4000)},M=()=>{if(!B)return;clearInterval(B),B=null},P=(q,{governanceRules:f,superAdmins:x}={})=>{if(!q||!f)return;D=q,F=f,H=x||[],q.sm.setGovernanceStateChangeCallback(({isActive:z,activeAddress:j})=>{if(z&&j&&J(j))L();else M()})};export{P as start};
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genosdb",
3
- "version": "0.14.1",
3
+ "version": "0.15.1",
4
4
  "description": "GenosDB (GDB): distributed graph database in real-time, peer-to-peer, scalable storage - efficient querying of complex relationships.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",