this.me 2.9.51 → 3.0.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/README.md +77 -82
- package/dist/this-me.cjs.js +55 -0
- package/dist/this-me.es.js +324 -0
- package/dist/this-me.umd.js +55 -0
- package/package.json +27 -19
- package/bin/me.cli.js +0 -99
- package/index.js +0 -12
- package/jsdoc.json +0 -41
- package/notes/Entonces_Que_es_me.md +0 -9
- package/notes/Index of this.me Structure.md +0 -154
- package/notes/Index.md +0 -134
- package/notes/Inmutabilidad_de_la_Identidad_basica.md +0 -44
- package/notes/Questions.md +0 -62
- package/notes/Summary.md +0 -125
- package/notes/The Problem: Decentralized Yet Trustworthy.md +0 -13
- package/notes/Understanding me && you && himContext.md +0 -11
- package/notes/hot_encoding.md +0 -44
- package/src/example.js +0 -25
- package/src/me.js +0 -148
- package/src/methods/attributes.js +0 -79
- package/src/methods/identity.js +0 -31
- package/src/methods/properties.js +0 -73
- package/src/methods/reactions.js +0 -31
- package/src/methods/relationships.js +0 -26
- package/src/scripts/setup.js +0 -19
- package/src/scripts/setup_validation.js +0 -31
package/README.md
CHANGED
|
@@ -5,62 +5,102 @@
|
|
|
5
5
|
|
|
6
6
|
<strong>.me</strong> is your identity that lives on your machine, under your control. It holds attributes, relationships, and keys that define who you are—and crucially, <strong>how you relate to others</strong>.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
# Getting Started:
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
You can use **this.me** both in the browser and in Node environments. The library automatically detects the environment and provides a single global instance of `me` once initialized.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
1. ##### **Install `this.me`:**
|
|
14
|
-
Open your terminal and run the following command to install the `this.me` package:
|
|
15
|
-
```js
|
|
16
|
-
npm i -g this.me
|
|
17
|
-
```
|
|
12
|
+
### **1. Installation**
|
|
18
13
|
|
|
19
|
-
|
|
14
|
+
If you are using npm:
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
```bash
|
|
17
|
+
npm install this.me
|
|
18
|
+
```
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
- An identifier (username)
|
|
27
|
-
- Keys (private/public — currently placeholders)
|
|
28
|
-
- User-defined attributes
|
|
29
|
-
- Relationships and other social elements (reactions, attributies, properties, endorsements...)
|
|
20
|
+
Or load it directly in the browser (after building):
|
|
30
21
|
|
|
31
|
-
|
|
22
|
+
```html
|
|
23
|
+
<script src="this.me.umd.js"></script>
|
|
24
|
+
<script>
|
|
25
|
+
// Global instance automatically attached to `window.me`
|
|
26
|
+
console.log(me); // Ready to use after initialization
|
|
27
|
+
</script>
|
|
28
|
+
```
|
|
32
29
|
|
|
33
|
-
|
|
30
|
+
---
|
|
34
31
|
|
|
35
|
-
**
|
|
32
|
+
### **2. Initialization**
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
You need to initialize the `.me` instance before using it:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import me from "this.me";
|
|
38
|
+
|
|
39
|
+
await me.init({
|
|
40
|
+
monadEndpoint: "http://localhost:7777" // optional, defaults to 7777
|
|
41
|
+
});
|
|
39
42
|
```
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
- **Flow**: Prompts for username and hash (secret key), then saves an encrypted file at ~/.this/me/username.me.
|
|
44
|
+
Once initialized, the `me` instance will maintain its state (status, loaded identities, etc.) globally.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
---
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
+
### **3. Checking Daemon Status**
|
|
49
|
+
|
|
50
|
+
You can verify if the local daemon is running:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
const status = await me.status();
|
|
54
|
+
console.log("Daemon active:", status.active);
|
|
48
55
|
```
|
|
49
56
|
|
|
50
|
-
|
|
51
|
-
- **Flow**:
|
|
52
|
-
- If [username] is not provided, it prompts for it.
|
|
53
|
-
- Always prompts for the hash to unlock the identity.
|
|
54
|
-
- If successful, prints the identity as JSON.
|
|
57
|
+
The floating components or any GUI indicators (green/red) can rely directly on `me.status()`.
|
|
55
58
|
|
|
56
|
-
|
|
59
|
+
---
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
### **4. Listing Identities**
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
const list = await me.listUs();
|
|
65
|
+
console.log(list);
|
|
66
|
+
/*
|
|
67
|
+
[
|
|
68
|
+
{ alias: "suign", path: "/Users/abellae/.this/me/suign" }
|
|
69
|
+
]
|
|
70
|
+
*/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### **5. Loading an Identity**
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
await me.load("abellae", "mySecretHash");
|
|
79
|
+
console.log(me.active); // true if identity is successfully loaded
|
|
60
80
|
```
|
|
61
81
|
|
|
62
|
-
|
|
63
|
-
|
|
82
|
+
After loading, you can use all available methods (`be`, `have`, `do`, etc.).
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### **6. Example in the Browser Console**
|
|
87
|
+
|
|
88
|
+
If you include the UMD bundle:
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<script src="this.me.umd.js"></script>
|
|
92
|
+
<script>
|
|
93
|
+
(async () => {
|
|
94
|
+
await me.init();
|
|
95
|
+
console.log(await me.status());
|
|
96
|
+
console.log(await me.listUs());
|
|
97
|
+
})();
|
|
98
|
+
</script>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- `me` is a **singleton instance** that lives in memory once initialized.
|
|
102
|
+
- Works in both browser and Node.
|
|
103
|
+
- Provides methods for status, identity management, and attribute handling.
|
|
64
104
|
|
|
65
105
|
------
|
|
66
106
|
|
|
@@ -118,18 +158,6 @@ Once unlocked, you can:
|
|
|
118
158
|
|
|
119
159
|
------
|
|
120
160
|
|
|
121
|
-
#### Locking the identity
|
|
122
|
-
|
|
123
|
-
You can clear the identity from memory with:
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
me.lock();
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
This keeps the encrypted file on disk but removes all data from RAM.
|
|
130
|
-
|
|
131
|
-
------
|
|
132
|
-
|
|
133
161
|
### **Summary**
|
|
134
162
|
|
|
135
163
|
- Your identity is encrypted on your own machine.
|
|
@@ -150,25 +178,6 @@ Let me know if you’d like a diagram or visual flow to go with this explanation
|
|
|
150
178
|
3. **Local Ownership**
|
|
151
179
|
All sensitive data (including private keys) stays on the user's machine.
|
|
152
180
|
|
|
153
|
-
---
|
|
154
|
-
### 📁 File Structure
|
|
155
|
-
* `~/.this/me/username.me.json` — Encrypted identity file
|
|
156
|
-
* `.me` includes:
|
|
157
|
-
|
|
158
|
-
* `username`
|
|
159
|
-
* `publicKey`, `privateKey` (encrypted)
|
|
160
|
-
* `attributes`, `relationships`, `reactions`, `properties`, `relationships`
|
|
161
|
-
* `endorsements`
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
### 🔐 Cryptographic Model
|
|
165
|
-
* Identity is unlocked using a user-defined `hash` (password).
|
|
166
|
-
* This hash decrypts the local `.me` file.
|
|
167
|
-
* The identity includes:
|
|
168
|
-
|
|
169
|
-
* A **key pair** (public/private) for signing and verification.
|
|
170
|
-
* Optional **endorsements** signed by Cleaker or other authorities.
|
|
171
|
-
|
|
172
181
|
---
|
|
173
182
|
### 🛡️ Security Model
|
|
174
183
|
* No private key ever leaves the local `.me` file.
|
|
@@ -180,17 +189,6 @@ Let me know if you’d like a diagram or visual flow to go with this explanation
|
|
|
180
189
|
* `.me` can be restored using a seed phrase or backup.
|
|
181
190
|
* New devices can be authorized using signatures from old devices.
|
|
182
191
|
|
|
183
|
-
---
|
|
184
|
-
## ⚖️ Responsibilities
|
|
185
|
-
* **this.me**
|
|
186
|
-
* Local file management, encryption, signing.
|
|
187
|
-
* CLI + API for usage.
|
|
188
|
-
|
|
189
|
-
* **Cleaker / Authorities**
|
|
190
|
-
|
|
191
|
-
* Store trusted records of `username` + `publicKey`
|
|
192
|
-
* Provide validation/endorsement services.
|
|
193
|
-
|
|
194
192
|
---
|
|
195
193
|
## 🌍 Use Cases
|
|
196
194
|
* Digital signature of documents
|
|
@@ -199,9 +197,6 @@ Let me know if you’d like a diagram or visual flow to go with this explanation
|
|
|
199
197
|
* Group identity and shared contexts (`me && you && them in context/friends`)
|
|
200
198
|
|
|
201
199
|
---
|
|
202
|
-
By default, **this.me** uses the **local file system (~/.this/me/)** to store and manage identity data.
|
|
203
|
-
No external service is required.
|
|
204
|
-
|
|
205
200
|
<img src="https://suign.github.io/assets/imgs/monads.png" alt="Cleak Me Please" width="244">Hello, I am **.me**
|
|
206
201
|
|
|
207
202
|
### ❯ add.me
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";class c{constructor(t,s){this.me=t,this.url=s,this.ws=null,this.reconnectInterval=1e4,this.isConnected=!1,this.connect()}connect(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{console.log("[this.me][WS] Connected to daemon"),this.isConnected=!0,this.me.state?.status&&(this.me.state.status.active=!0,this.me.state.status.error=!1),this.#t()},this.ws.onmessage=t=>{try{const s=JSON.parse(t.data);this.#s(s)}catch{console.warn("[this.me][WS] Invalid message:",t.data)}},this.ws.onclose=()=>{console.warn("[this.me][WS] Disconnected, retrying in 10s"),this.isConnected=!1,this.me.state?.status&&(this.me.state.status.active=!1,this.me.state.status.error=!0),this.#t(),setTimeout(()=>this.connect(),this.reconnectInterval)},this.ws.onerror=t=>{console.error("[this.me][WS] Error:",t),this.ws.close()}}#s(t){switch(t.type){case"status":this.me.state.status={active:t.data.active,error:!1,data:t.data};break;case"listUs":this.me.state.listUs=t.data;break;case"update":console.log("[this.me][WS] Update event:",t.data);break;default:console.warn("[this.me][WS] Unknown message type:",t.type)}this.#t()}send(t,s){this.isConnected&&this.ws.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify({type:t,data:s}))}#t(){this.me.subscribers?.size&&this.me.subscribers.forEach(t=>t(this.me.state))}}class u{constructor(t="http://localhost:7777/graphql"){this.endpoint=t,this.state={status:{active:!1,error:!1,loading:!0,data:null},listUs:[],activeMe:null},this.subscribers=new Set,this.status(),this.socket=null}async init(){return this.#s({status:{...this.state.status,loading:!0}}),(await this.status()).active&&(await this.startSocket(),await new Promise(s=>{let a=!1;const e=this.subscribe(i=>{!a&&i.status.active!==void 0&&(a=!0,e(),s())});setTimeout(()=>{a||(a=!0,e(),s())},2e3)})),this.#s({status:{...this.state.status,loading:!1}}),this.state.status}async startSocket(){if(this.state.status.active){if(this.socket){console.warn("[this.me] WebSocket already running");return}this.socket=new c(this.endpoint.replace("/graphql","")),this.socket.on("status",t=>{this._updateFromSocket({status:{active:!0,error:!1,data:t}})}),this.socket.on("listUs",t=>{this._updateFromSocket({listUs:t})}),this.socket.on("update",t=>{console.log("[this.me] update event",t)})}}_updateFromSocket(t){this.#s(t)}setEndpoint(t){typeof t=="string"&&t.trim()!==""&&(this.endpoint=t)}getState(){return this.state}#s(t){this.state={...this.state,...t},this.subscribers.forEach(s=>s(this.state))}subscribe(t){return this.subscribers.add(t),()=>this.subscribers.delete(t)}async#t(t,s={}){const a=await fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:t,variables:s})});if(!a.ok)throw new Error(`GraphQL error: ${a.status}`);const{data:e,errors:i}=await a.json();if(i)throw new Error(i.map(o=>o.message).join(", "));return e}async status(){const t=`
|
|
2
|
+
query {
|
|
3
|
+
status {
|
|
4
|
+
active
|
|
5
|
+
version
|
|
6
|
+
uptime
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
`;try{const s=await this.#t(t),a=s.status?{active:s.status.active,version:s.status.version,uptime:s.status.uptime}:{active:!1,version:null,uptime:null};return this.#s({status:{active:a.active,error:!1,data:a}}),a}catch{const s={active:!1,version:null,uptime:null};return this.#s({status:{active:!1,error:!0,data:null}}),s}}async listUs(){const t=`
|
|
10
|
+
query {
|
|
11
|
+
listUs {
|
|
12
|
+
alias
|
|
13
|
+
path
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
`;try{const s=await this.#t(t),a=Array.isArray(s.listUs)?s.listUs.map(({alias:e,path:i})=>({alias:e,path:i})):[];return this.#s({listUs:a}),a}catch{return this.#s({listUs:[]}),[]}}async loadMe(t,s){const a=`
|
|
17
|
+
mutation($alias: String!, $hash: String!) {
|
|
18
|
+
loadMe(alias: $alias, hash: $hash)
|
|
19
|
+
}
|
|
20
|
+
`;try{const i=!!(await this.#t(a,{alias:t,hash:s})).loadMe;return i&&this.#s({activeMe:t}),i}catch{return!1}}async be(t,s,a){const e=`
|
|
21
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
22
|
+
be(alias: $alias, key: $key, value: $value)
|
|
23
|
+
}
|
|
24
|
+
`;try{return!!(await this.#t(e,{alias:t,key:s,value:a})).be}catch{return!1}}async have(t,s,a){const e=`
|
|
25
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
26
|
+
have(alias: $alias, key: $key, value: $value)
|
|
27
|
+
}
|
|
28
|
+
`;try{return!!(await this.#t(e,{alias:t,key:s,value:a})).have}catch{return!1}}async do_(t,s,a){const e=`
|
|
29
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
30
|
+
do(alias: $alias, key: $key, value: $value)
|
|
31
|
+
}
|
|
32
|
+
`;try{return!!(await this.#t(e,{alias:t,key:s,value:a})).do}catch{return!1}}async at(t,s,a){const e=`
|
|
33
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
34
|
+
at(alias: $alias, key: $key, value: $value)
|
|
35
|
+
}
|
|
36
|
+
`;try{return!!(await this.#t(e,{alias:t,key:s,value:a})).at}catch{return!1}}async relate(t,s,a){const e=`
|
|
37
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
38
|
+
relate(alias: $alias, key: $key, value: $value)
|
|
39
|
+
}
|
|
40
|
+
`;try{return!!(await this.#t(e,{alias:t,key:s,value:a})).relate}catch{return!1}}async react(t,s,a){const e=`
|
|
41
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
42
|
+
react(alias: $alias, key: $key, value: $value)
|
|
43
|
+
}
|
|
44
|
+
`;try{return!!(await this.#t(e,{alias:t,key:s,value:a})).react}catch{return!1}}async communication(t,s,a){const e=`
|
|
45
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
46
|
+
communication(alias: $alias, key: $key, value: $value)
|
|
47
|
+
}
|
|
48
|
+
`;try{return!!(await this.#t(e,{alias:t,key:s,value:a})).communication}catch{return!1}}async me(t){const s=`
|
|
49
|
+
query($alias: String!) {
|
|
50
|
+
me(alias: $alias) {
|
|
51
|
+
alias
|
|
52
|
+
publicKey
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
`;try{const a=await this.#t(s,{alias:t});if(a.me&&typeof a.me=="object"){const{alias:e,publicKey:i}=a.me;return e&&i?{alias:e,publicKey:i}:null}return null}catch{return null}}}const n=new u;typeof window<"u"&&(window.me=n,console.log("[this.me] Global instance available as window.me"));module.exports=n;
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
class o {
|
|
2
|
+
constructor(t, s) {
|
|
3
|
+
this.me = t, this.url = s, this.ws = null, this.reconnectInterval = 1e4, this.isConnected = !1, this.connect();
|
|
4
|
+
}
|
|
5
|
+
connect() {
|
|
6
|
+
this.ws = new WebSocket(this.url), this.ws.onopen = () => {
|
|
7
|
+
console.log("[this.me][WS] Connected to daemon"), this.isConnected = !0, this.me.state?.status && (this.me.state.status.active = !0, this.me.state.status.error = !1), this.#t();
|
|
8
|
+
}, this.ws.onmessage = (t) => {
|
|
9
|
+
try {
|
|
10
|
+
const s = JSON.parse(t.data);
|
|
11
|
+
this.#s(s);
|
|
12
|
+
} catch {
|
|
13
|
+
console.warn("[this.me][WS] Invalid message:", t.data);
|
|
14
|
+
}
|
|
15
|
+
}, this.ws.onclose = () => {
|
|
16
|
+
console.warn("[this.me][WS] Disconnected, retrying in 10s"), this.isConnected = !1, this.me.state?.status && (this.me.state.status.active = !1, this.me.state.status.error = !0), this.#t(), setTimeout(() => this.connect(), this.reconnectInterval);
|
|
17
|
+
}, this.ws.onerror = (t) => {
|
|
18
|
+
console.error("[this.me][WS] Error:", t), this.ws.close();
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
#s(t) {
|
|
22
|
+
switch (t.type) {
|
|
23
|
+
case "status":
|
|
24
|
+
this.me.state.status = {
|
|
25
|
+
active: t.data.active,
|
|
26
|
+
error: !1,
|
|
27
|
+
data: t.data
|
|
28
|
+
};
|
|
29
|
+
break;
|
|
30
|
+
case "listUs":
|
|
31
|
+
this.me.state.listUs = t.data;
|
|
32
|
+
break;
|
|
33
|
+
case "update":
|
|
34
|
+
console.log("[this.me][WS] Update event:", t.data);
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
console.warn("[this.me][WS] Unknown message type:", t.type);
|
|
38
|
+
}
|
|
39
|
+
this.#t();
|
|
40
|
+
}
|
|
41
|
+
send(t, s) {
|
|
42
|
+
this.isConnected && this.ws.readyState === WebSocket.OPEN && this.ws.send(JSON.stringify({ type: t, data: s }));
|
|
43
|
+
}
|
|
44
|
+
#t() {
|
|
45
|
+
this.me.subscribers?.size && this.me.subscribers.forEach((t) => t(this.me.state));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
class c {
|
|
49
|
+
constructor(t = "http://localhost:7777/graphql") {
|
|
50
|
+
this.endpoint = t, this.state = {
|
|
51
|
+
status: { active: !1, error: !1, loading: !0, data: null },
|
|
52
|
+
listUs: [],
|
|
53
|
+
activeMe: null
|
|
54
|
+
}, this.subscribers = /* @__PURE__ */ new Set(), this.status(), this.socket = null;
|
|
55
|
+
}
|
|
56
|
+
/** 🔹 Init
|
|
57
|
+
* Manually initializes the daemon state (status + listUs).
|
|
58
|
+
* Useful if you need to re-check after user actions.
|
|
59
|
+
*/
|
|
60
|
+
async init() {
|
|
61
|
+
return this.#s({
|
|
62
|
+
status: { ...this.state.status, loading: !0 }
|
|
63
|
+
}), (await this.status()).active && (await this.startSocket(), await new Promise((s) => {
|
|
64
|
+
let a = !1;
|
|
65
|
+
const e = this.subscribe((i) => {
|
|
66
|
+
!a && i.status.active !== void 0 && (a = !0, e(), s());
|
|
67
|
+
});
|
|
68
|
+
setTimeout(() => {
|
|
69
|
+
a || (a = !0, e(), s());
|
|
70
|
+
}, 2e3);
|
|
71
|
+
})), this.#s({
|
|
72
|
+
status: { ...this.state.status, loading: !1 }
|
|
73
|
+
}), this.state.status;
|
|
74
|
+
}
|
|
75
|
+
async startSocket() {
|
|
76
|
+
if (this.state.status.active) {
|
|
77
|
+
if (this.socket) {
|
|
78
|
+
console.warn("[this.me] WebSocket already running");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.socket = new o(this.endpoint.replace("/graphql", "")), this.socket.on("status", (t) => {
|
|
82
|
+
this._updateFromSocket({
|
|
83
|
+
status: { active: !0, error: !1, data: t }
|
|
84
|
+
});
|
|
85
|
+
}), this.socket.on("listUs", (t) => {
|
|
86
|
+
this._updateFromSocket({ listUs: t });
|
|
87
|
+
}), this.socket.on("update", (t) => {
|
|
88
|
+
console.log("[this.me] update event", t);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
_updateFromSocket(t) {
|
|
93
|
+
this.#s(t);
|
|
94
|
+
}
|
|
95
|
+
setEndpoint(t) {
|
|
96
|
+
typeof t == "string" && t.trim() !== "" && (this.endpoint = t);
|
|
97
|
+
}
|
|
98
|
+
getState() {
|
|
99
|
+
return this.state;
|
|
100
|
+
}
|
|
101
|
+
#s(t) {
|
|
102
|
+
this.state = { ...this.state, ...t }, this.subscribers.forEach((s) => s(this.state));
|
|
103
|
+
}
|
|
104
|
+
subscribe(t) {
|
|
105
|
+
return this.subscribers.add(t), () => this.subscribers.delete(t);
|
|
106
|
+
}
|
|
107
|
+
async #t(t, s = {}) {
|
|
108
|
+
const a = await fetch(this.endpoint, {
|
|
109
|
+
method: "POST",
|
|
110
|
+
headers: { "Content-Type": "application/json" },
|
|
111
|
+
body: JSON.stringify({ query: t, variables: s })
|
|
112
|
+
});
|
|
113
|
+
if (!a.ok) throw new Error(`GraphQL error: ${a.status}`);
|
|
114
|
+
const { data: e, errors: i } = await a.json();
|
|
115
|
+
if (i) throw new Error(i.map((r) => r.message).join(", "));
|
|
116
|
+
return e;
|
|
117
|
+
}
|
|
118
|
+
// 🔹 Daemon-level helpers
|
|
119
|
+
/** 🔹 Daemon status
|
|
120
|
+
* Retrieves the current status of the daemon.
|
|
121
|
+
* Use to check if the service is active and get version/uptime info.
|
|
122
|
+
*/
|
|
123
|
+
async status() {
|
|
124
|
+
const t = `
|
|
125
|
+
query {
|
|
126
|
+
status {
|
|
127
|
+
active
|
|
128
|
+
version
|
|
129
|
+
uptime
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
try {
|
|
134
|
+
const s = await this.#t(t), a = s.status ? {
|
|
135
|
+
active: s.status.active,
|
|
136
|
+
version: s.status.version,
|
|
137
|
+
uptime: s.status.uptime
|
|
138
|
+
} : { active: !1, version: null, uptime: null };
|
|
139
|
+
return this.#s({ status: { active: a.active, error: !1, data: a } }), a;
|
|
140
|
+
} catch {
|
|
141
|
+
const s = { active: !1, version: null, uptime: null };
|
|
142
|
+
return this.#s({ status: { active: !1, error: !0, data: null } }), s;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** 🔹 List all identities
|
|
146
|
+
* Fetches all available identities (users).
|
|
147
|
+
* Use to display or manage the list of identities.
|
|
148
|
+
*/
|
|
149
|
+
async listUs() {
|
|
150
|
+
const t = `
|
|
151
|
+
query {
|
|
152
|
+
listUs {
|
|
153
|
+
alias
|
|
154
|
+
path
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
`;
|
|
158
|
+
try {
|
|
159
|
+
const s = await this.#t(t), a = Array.isArray(s.listUs) ? s.listUs.map(({ alias: e, path: i }) => ({ alias: e, path: i })) : [];
|
|
160
|
+
return this.#s({ listUs: a }), a;
|
|
161
|
+
} catch {
|
|
162
|
+
return this.#s({ listUs: [] }), [];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/** 🔹 Load an identity
|
|
166
|
+
* Loads a specific identity by alias and hash.
|
|
167
|
+
* Use to activate or switch to a particular identity.
|
|
168
|
+
*/
|
|
169
|
+
async loadMe(t, s) {
|
|
170
|
+
const a = `
|
|
171
|
+
mutation($alias: String!, $hash: String!) {
|
|
172
|
+
loadMe(alias: $alias, hash: $hash)
|
|
173
|
+
}
|
|
174
|
+
`;
|
|
175
|
+
try {
|
|
176
|
+
const i = !!(await this.#t(a, { alias: t, hash: s })).loadMe;
|
|
177
|
+
return i && this.#s({ activeMe: t }), i;
|
|
178
|
+
} catch {
|
|
179
|
+
return !1;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// 🔹 Me-level operations
|
|
183
|
+
/** 🔹 Be operation
|
|
184
|
+
* Performs a 'be' mutation for given alias, key, and value.
|
|
185
|
+
* Use to set or update identity attributes.
|
|
186
|
+
*/
|
|
187
|
+
async be(t, s, a) {
|
|
188
|
+
const e = `
|
|
189
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
190
|
+
be(alias: $alias, key: $key, value: $value)
|
|
191
|
+
}
|
|
192
|
+
`;
|
|
193
|
+
try {
|
|
194
|
+
return !!(await this.#t(e, { alias: t, key: s, value: a })).be;
|
|
195
|
+
} catch {
|
|
196
|
+
return !1;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/** 🔹 Have operation
|
|
200
|
+
* Performs a 'have' mutation for given alias, key, and value.
|
|
201
|
+
* Use to declare possession or ownership related to identity.
|
|
202
|
+
*/
|
|
203
|
+
async have(t, s, a) {
|
|
204
|
+
const e = `
|
|
205
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
206
|
+
have(alias: $alias, key: $key, value: $value)
|
|
207
|
+
}
|
|
208
|
+
`;
|
|
209
|
+
try {
|
|
210
|
+
return !!(await this.#t(e, { alias: t, key: s, value: a })).have;
|
|
211
|
+
} catch {
|
|
212
|
+
return !1;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/** 🔹 Do operation
|
|
216
|
+
* Performs a 'do' mutation for given alias, key, and value.
|
|
217
|
+
* Use to record actions or activities for the identity.
|
|
218
|
+
*/
|
|
219
|
+
async do_(t, s, a) {
|
|
220
|
+
const e = `
|
|
221
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
222
|
+
do(alias: $alias, key: $key, value: $value)
|
|
223
|
+
}
|
|
224
|
+
`;
|
|
225
|
+
try {
|
|
226
|
+
return !!(await this.#t(e, { alias: t, key: s, value: a })).do;
|
|
227
|
+
} catch {
|
|
228
|
+
return !1;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** 🔹 At operation
|
|
232
|
+
* Performs an 'at' mutation for given alias, key, and value.
|
|
233
|
+
* Use to set location or context related data for the identity.
|
|
234
|
+
*/
|
|
235
|
+
async at(t, s, a) {
|
|
236
|
+
const e = `
|
|
237
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
238
|
+
at(alias: $alias, key: $key, value: $value)
|
|
239
|
+
}
|
|
240
|
+
`;
|
|
241
|
+
try {
|
|
242
|
+
return !!(await this.#t(e, { alias: t, key: s, value: a })).at;
|
|
243
|
+
} catch {
|
|
244
|
+
return !1;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/** 🔹 Relate operation
|
|
248
|
+
* Performs a 'relate' mutation for given alias, key, and value.
|
|
249
|
+
* Use to define relationships or connections for the identity.
|
|
250
|
+
*/
|
|
251
|
+
async relate(t, s, a) {
|
|
252
|
+
const e = `
|
|
253
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
254
|
+
relate(alias: $alias, key: $key, value: $value)
|
|
255
|
+
}
|
|
256
|
+
`;
|
|
257
|
+
try {
|
|
258
|
+
return !!(await this.#t(e, { alias: t, key: s, value: a })).relate;
|
|
259
|
+
} catch {
|
|
260
|
+
return !1;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/** 🔹 React operation
|
|
264
|
+
* Performs a 'react' mutation for given alias, key, and value.
|
|
265
|
+
* Use to record reactions or responses by the identity.
|
|
266
|
+
*/
|
|
267
|
+
async react(t, s, a) {
|
|
268
|
+
const e = `
|
|
269
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
270
|
+
react(alias: $alias, key: $key, value: $value)
|
|
271
|
+
}
|
|
272
|
+
`;
|
|
273
|
+
try {
|
|
274
|
+
return !!(await this.#t(e, { alias: t, key: s, value: a })).react;
|
|
275
|
+
} catch {
|
|
276
|
+
return !1;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/** 🔹 Communication operation
|
|
280
|
+
* Performs a 'communication' mutation for given alias, key, and value.
|
|
281
|
+
* Use to log communications or messages for the identity.
|
|
282
|
+
*/
|
|
283
|
+
async communication(t, s, a) {
|
|
284
|
+
const e = `
|
|
285
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
286
|
+
communication(alias: $alias, key: $key, value: $value)
|
|
287
|
+
}
|
|
288
|
+
`;
|
|
289
|
+
try {
|
|
290
|
+
return !!(await this.#t(e, { alias: t, key: s, value: a })).communication;
|
|
291
|
+
} catch {
|
|
292
|
+
return !1;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/** 🔹 Get identity info
|
|
296
|
+
* Queries detailed information about a specific identity by alias.
|
|
297
|
+
* Use to retrieve public data like alias and publicKey.
|
|
298
|
+
*/
|
|
299
|
+
async me(t) {
|
|
300
|
+
const s = `
|
|
301
|
+
query($alias: String!) {
|
|
302
|
+
me(alias: $alias) {
|
|
303
|
+
alias
|
|
304
|
+
publicKey
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
`;
|
|
308
|
+
try {
|
|
309
|
+
const a = await this.#t(s, { alias: t });
|
|
310
|
+
if (a.me && typeof a.me == "object") {
|
|
311
|
+
const { alias: e, publicKey: i } = a.me;
|
|
312
|
+
return e && i ? { alias: e, publicKey: i } : null;
|
|
313
|
+
}
|
|
314
|
+
return null;
|
|
315
|
+
} catch {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const u = new c();
|
|
321
|
+
typeof window < "u" && (window.me = u, console.log("[this.me] Global instance available as window.me"));
|
|
322
|
+
export {
|
|
323
|
+
u as default
|
|
324
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
(function(n,r){typeof exports=="object"&&typeof module<"u"?module.exports=r():typeof define=="function"&&define.amd?define(r):(n=typeof globalThis<"u"?globalThis:n||self,n.Me=r())})(this,function(){"use strict";class n{constructor(t,s){this.me=t,this.url=s,this.ws=null,this.reconnectInterval=1e4,this.isConnected=!1,this.connect()}connect(){this.ws=new WebSocket(this.url),this.ws.onopen=()=>{console.log("[this.me][WS] Connected to daemon"),this.isConnected=!0,this.me.state?.status&&(this.me.state.status.active=!0,this.me.state.status.error=!1),this.#t()},this.ws.onmessage=t=>{try{const s=JSON.parse(t.data);this.#s(s)}catch{console.warn("[this.me][WS] Invalid message:",t.data)}},this.ws.onclose=()=>{console.warn("[this.me][WS] Disconnected, retrying in 10s"),this.isConnected=!1,this.me.state?.status&&(this.me.state.status.active=!1,this.me.state.status.error=!0),this.#t(),setTimeout(()=>this.connect(),this.reconnectInterval)},this.ws.onerror=t=>{console.error("[this.me][WS] Error:",t),this.ws.close()}}#s(t){switch(t.type){case"status":this.me.state.status={active:t.data.active,error:!1,data:t.data};break;case"listUs":this.me.state.listUs=t.data;break;case"update":console.log("[this.me][WS] Update event:",t.data);break;default:console.warn("[this.me][WS] Unknown message type:",t.type)}this.#t()}send(t,s){this.isConnected&&this.ws.readyState===WebSocket.OPEN&&this.ws.send(JSON.stringify({type:t,data:s}))}#t(){this.me.subscribers?.size&&this.me.subscribers.forEach(t=>t(this.me.state))}}class r{constructor(t="http://localhost:7777/graphql"){this.endpoint=t,this.state={status:{active:!1,error:!1,loading:!0,data:null},listUs:[],activeMe:null},this.subscribers=new Set,this.status(),this.socket=null}async init(){return this.#s({status:{...this.state.status,loading:!0}}),(await this.status()).active&&(await this.startSocket(),await new Promise(s=>{let e=!1;const a=this.subscribe(i=>{!e&&i.status.active!==void 0&&(e=!0,a(),s())});setTimeout(()=>{e||(e=!0,a(),s())},2e3)})),this.#s({status:{...this.state.status,loading:!1}}),this.state.status}async startSocket(){if(this.state.status.active){if(this.socket){console.warn("[this.me] WebSocket already running");return}this.socket=new n(this.endpoint.replace("/graphql","")),this.socket.on("status",t=>{this._updateFromSocket({status:{active:!0,error:!1,data:t}})}),this.socket.on("listUs",t=>{this._updateFromSocket({listUs:t})}),this.socket.on("update",t=>{console.log("[this.me] update event",t)})}}_updateFromSocket(t){this.#s(t)}setEndpoint(t){typeof t=="string"&&t.trim()!==""&&(this.endpoint=t)}getState(){return this.state}#s(t){this.state={...this.state,...t},this.subscribers.forEach(s=>s(this.state))}subscribe(t){return this.subscribers.add(t),()=>this.subscribers.delete(t)}async#t(t,s={}){const e=await fetch(this.endpoint,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:t,variables:s})});if(!e.ok)throw new Error(`GraphQL error: ${e.status}`);const{data:a,errors:i}=await e.json();if(i)throw new Error(i.map(u=>u.message).join(", "));return a}async status(){const t=`
|
|
2
|
+
query {
|
|
3
|
+
status {
|
|
4
|
+
active
|
|
5
|
+
version
|
|
6
|
+
uptime
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
`;try{const s=await this.#t(t),e=s.status?{active:s.status.active,version:s.status.version,uptime:s.status.uptime}:{active:!1,version:null,uptime:null};return this.#s({status:{active:e.active,error:!1,data:e}}),e}catch{const s={active:!1,version:null,uptime:null};return this.#s({status:{active:!1,error:!0,data:null}}),s}}async listUs(){const t=`
|
|
10
|
+
query {
|
|
11
|
+
listUs {
|
|
12
|
+
alias
|
|
13
|
+
path
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
`;try{const s=await this.#t(t),e=Array.isArray(s.listUs)?s.listUs.map(({alias:a,path:i})=>({alias:a,path:i})):[];return this.#s({listUs:e}),e}catch{return this.#s({listUs:[]}),[]}}async loadMe(t,s){const e=`
|
|
17
|
+
mutation($alias: String!, $hash: String!) {
|
|
18
|
+
loadMe(alias: $alias, hash: $hash)
|
|
19
|
+
}
|
|
20
|
+
`;try{const i=!!(await this.#t(e,{alias:t,hash:s})).loadMe;return i&&this.#s({activeMe:t}),i}catch{return!1}}async be(t,s,e){const a=`
|
|
21
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
22
|
+
be(alias: $alias, key: $key, value: $value)
|
|
23
|
+
}
|
|
24
|
+
`;try{return!!(await this.#t(a,{alias:t,key:s,value:e})).be}catch{return!1}}async have(t,s,e){const a=`
|
|
25
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
26
|
+
have(alias: $alias, key: $key, value: $value)
|
|
27
|
+
}
|
|
28
|
+
`;try{return!!(await this.#t(a,{alias:t,key:s,value:e})).have}catch{return!1}}async do_(t,s,e){const a=`
|
|
29
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
30
|
+
do(alias: $alias, key: $key, value: $value)
|
|
31
|
+
}
|
|
32
|
+
`;try{return!!(await this.#t(a,{alias:t,key:s,value:e})).do}catch{return!1}}async at(t,s,e){const a=`
|
|
33
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
34
|
+
at(alias: $alias, key: $key, value: $value)
|
|
35
|
+
}
|
|
36
|
+
`;try{return!!(await this.#t(a,{alias:t,key:s,value:e})).at}catch{return!1}}async relate(t,s,e){const a=`
|
|
37
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
38
|
+
relate(alias: $alias, key: $key, value: $value)
|
|
39
|
+
}
|
|
40
|
+
`;try{return!!(await this.#t(a,{alias:t,key:s,value:e})).relate}catch{return!1}}async react(t,s,e){const a=`
|
|
41
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
42
|
+
react(alias: $alias, key: $key, value: $value)
|
|
43
|
+
}
|
|
44
|
+
`;try{return!!(await this.#t(a,{alias:t,key:s,value:e})).react}catch{return!1}}async communication(t,s,e){const a=`
|
|
45
|
+
mutation($alias: String!, $key: String!, $value: String!) {
|
|
46
|
+
communication(alias: $alias, key: $key, value: $value)
|
|
47
|
+
}
|
|
48
|
+
`;try{return!!(await this.#t(a,{alias:t,key:s,value:e})).communication}catch{return!1}}async me(t){const s=`
|
|
49
|
+
query($alias: String!) {
|
|
50
|
+
me(alias: $alias) {
|
|
51
|
+
alias
|
|
52
|
+
publicKey
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
`;try{const e=await this.#t(s,{alias:t});if(e.me&&typeof e.me=="object"){const{alias:a,publicKey:i}=e.me;return a&&i?{alias:a,publicKey:i}:null}return null}catch{return null}}}const o=new r;return typeof window<"u"&&(window.me=o,console.log("[this.me] Global instance available as window.me")),o});
|