this.me 2.9.43 → 2.9.51
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/LICENSE +0 -0
- package/README.md +187 -50
- package/bin/me.cli.js +99 -0
- package/index.js +6 -4
- package/jsdoc.json +0 -0
- package/notes/Entonces_Que_es_me.md +9 -0
- package/notes/Index of this.me Structure.md +154 -0
- package/notes/Index.md +0 -0
- package/notes/Inmutabilidad_de_la_Identidad_basica.md +0 -0
- package/notes/Questions.md +0 -0
- package/notes/Summary.md +125 -0
- package/notes/The Problem: Decentralized Yet Trustworthy.md +13 -0
- package/notes/Understanding me && you && himContext.md +11 -0
- package/notes/hot_encoding.md +0 -0
- package/package.json +4 -3
- package/src/example.js +0 -0
- package/src/me.js +128 -34
- package/src/methods/attributes.js +79 -0
- package/src/methods/identity.js +31 -0
- package/src/methods/properties.js +73 -0
- package/src/methods/reactions.js +31 -0
- package/src/methods/relationships.js +26 -0
- package/src/scripts/setup.js +19 -0
- package/src/scripts/setup_validation.js +31 -0
- package/src/.me.cli.js +0 -20
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,77 +1,214 @@
|
|
|
1
1
|
<img src="https://docs.neurons.me/media/all-this/webP/this.me.webp" alt="SVG Image" width="250" height="250">
|
|
2
2
|
|
|
3
3
|
# THIS.ME
|
|
4
|
-
> **This.Me** is a data-structured identity designed to generate and manage identities, attributes, properties and more.
|
|
4
|
+
> **This.Me** is a data-structured identity designed to generate and manage identities, attributes, properties and more. It combines privacy, user control, and secure interoperability.
|
|
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
|
+
|
|
8
|
+
Each <strong>.me</strong> instance can pair with other authorities or identities using its <strong>cryptographic keys</strong>, establishing <strong>trust through signatures and endorsements</strong>.
|
|
9
|
+
|
|
10
|
+
Instead of logging in through third-party services, you can validate your identity or vouch for someone else’s using these key exchanges. This enables a decentralized trust model where relationships are verifiable, persistent, and portable.
|
|
7
11
|
|
|
12
|
+
# Getting Started:
|
|
8
13
|
1. ##### **Install `this.me`:**
|
|
9
14
|
Open your terminal and run the following command to install the `this.me` package:
|
|
10
15
|
```js
|
|
11
|
-
npm
|
|
16
|
+
npm i -g this.me
|
|
12
17
|
```
|
|
13
|
-
|
|
14
|
-
2.
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**Explanation**
|
|
21
|
-
• The **be** method in the **Me** class accepts an object of **key-value pairs** and **adds these to the identity object**.
|
|
22
|
-
• You can call **me.be()** multiple times with different attributes to dynamically update the identity object.
|
|
23
|
-
|
|
24
|
-
```javascript
|
|
25
|
-
// Create a new Me instance
|
|
26
|
-
let me = new Me("xyxyxy");
|
|
27
|
-
|
|
28
|
-
// Add attributes to the identity
|
|
29
|
-
me.be({ a: "XXX", b: "YYY" });
|
|
30
|
-
me.be({ c: "z" });
|
|
18
|
+
|
|
19
|
+
2. **Run this command on your terminal:**
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
me
|
|
31
23
|
```
|
|
32
24
|
|
|
33
|
-
**
|
|
25
|
+
The **Me** class represents a **persistent identity**, stored as an encrypted file (username.me) in ~/.this/me. This file contains:
|
|
26
|
+
- An identifier (username)
|
|
27
|
+
- Keys (private/public — currently placeholders)
|
|
28
|
+
- User-defined attributes
|
|
29
|
+
- Relationships and other social elements (reactions, attributies, properties, endorsements...)
|
|
30
|
+
|
|
31
|
+
It can be **created**, **read** (if you have the correct hash), **modified in memory**, and then **saved again** in encrypted form.
|
|
32
|
+
|
|
33
|
+
# Command Line Options:
|
|
34
|
+
|
|
35
|
+
**Run this commands on your terminal:**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
me create
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **Description**: Creates a new .me identity.
|
|
42
|
+
- **Flow**: Prompts for username and hash (secret key), then saves an encrypted file at ~/.this/me/username.me.
|
|
43
|
+
|
|
44
|
+
------
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
me show [username]
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- **Description**: Shows the decrypted contents of an identity.
|
|
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.
|
|
55
|
+
|
|
56
|
+
------
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
me list
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
- **Description**: Lists all local .me identities.
|
|
63
|
+
- **Flow**: Reads the ~/.this/me directory and prints all .me files (usernames).
|
|
64
|
+
|
|
65
|
+
------
|
|
66
|
+
|
|
67
|
+
# How this.me **Works (Simplified)**
|
|
68
|
+
|
|
69
|
+
The Me class creates and manages a **local, encrypted identity file** based on a username and a secret hash.
|
|
70
|
+
|
|
71
|
+
#### **Creating a new identity**
|
|
72
|
+
|
|
73
|
+
When you run:
|
|
34
74
|
|
|
35
75
|
```js
|
|
36
|
-
|
|
37
|
-
me.be({ name: "Alice", phone: "33550000" });
|
|
76
|
+
Me.create('abellae', 'mySecretHash');
|
|
38
77
|
```
|
|
39
78
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
79
|
+
It does the following:
|
|
80
|
+
|
|
81
|
+
- Builds a .me file path: ~/.this/me/abellae.me.
|
|
82
|
+
- Creates some **identity data** (username, keys, attributes, etc.).
|
|
83
|
+
- Uses the hash to **encrypt** that data with AES-256-CBC:
|
|
84
|
+
- It generates a random iv (initialization vector).
|
|
85
|
+
- Derives a key from the hash (sha256(hash)).
|
|
86
|
+
- Stores the encrypted result as iv + encryptedData.
|
|
87
|
+
|
|
88
|
+
> 🔒 The hash is **never saved** — it’s just used as a secret key.
|
|
43
89
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
90
|
+
------
|
|
91
|
+
|
|
92
|
+
#### Loading an existing identity
|
|
93
|
+
|
|
94
|
+
When you run:
|
|
48
95
|
|
|
49
|
-
**Implementation:**
|
|
50
96
|
```js
|
|
51
|
-
|
|
52
|
-
const config = {
|
|
53
|
-
registryURL: 'https://registry.neurons.me', // Registry authority URL
|
|
54
|
-
};
|
|
55
|
-
let me = new Me('alice', config);
|
|
56
|
-
me.register({ password: 'securePass123', email: 'alice@example.com' });
|
|
57
|
-
// Verify and interact with services using the connected registry
|
|
97
|
+
Me.load('abellae', 'mySecretHash');
|
|
58
98
|
```
|
|
59
99
|
|
|
60
|
-
|
|
100
|
+
It:
|
|
101
|
+
|
|
102
|
+
- Reads the encrypted .me file.
|
|
103
|
+
- Extracts the first 16 bytes as iv.
|
|
104
|
+
- Recomputes the key from the given hash.
|
|
105
|
+
- Tries to decrypt the file.
|
|
106
|
+
- If it works, it unlocks the identity and loads the data into memory.
|
|
107
|
+
|
|
108
|
+
------
|
|
109
|
+
|
|
110
|
+
#### **Using the unlocked identity**
|
|
111
|
+
|
|
112
|
+
Once unlocked, you can:
|
|
113
|
+
|
|
114
|
+
- Set attributes: me.be('developer', true)
|
|
115
|
+
- Add endorsements: me.addEndorsement(...)
|
|
116
|
+
- View attributes: me.getAttributes()
|
|
117
|
+
- Save updates with: me.save('mySecretHash')
|
|
118
|
+
|
|
119
|
+
------
|
|
120
|
+
|
|
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
|
+
### **Summary**
|
|
134
|
+
|
|
135
|
+
- Your identity is encrypted on your own machine.
|
|
136
|
+
- Only the correct hash can unlock it.
|
|
137
|
+
- No third parties are involved.
|
|
138
|
+
- The .me file is secure, portable, and self-owned.
|
|
139
|
+
|
|
140
|
+
Let me know if you’d like a diagram or visual flow to go with this explanation!
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
### 🔍 Core Principles
|
|
145
|
+
|
|
146
|
+
1. **Freedom to Declare**
|
|
147
|
+
Anyone can generate a `.me` identity locally without external approval.
|
|
148
|
+
2. **Trusted Endorsements**
|
|
149
|
+
Authorities (e.g., Cleaker) can endorse `.me` identities without controlling them.
|
|
150
|
+
3. **Local Ownership**
|
|
151
|
+
All sensitive data (including private keys) stays on the user's machine.
|
|
152
|
+
|
|
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
|
+
---
|
|
173
|
+
### 🛡️ Security Model
|
|
174
|
+
* No private key ever leaves the local `.me` file.
|
|
175
|
+
* Endorsements are public and verifiable using the public key.
|
|
176
|
+
* If compromised, user can rotate keys and notify authorities.
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
## 🌐 Multi-Device Support
|
|
180
|
+
* `.me` can be restored using a seed phrase or backup.
|
|
181
|
+
* New devices can be authorized using signatures from old devices.
|
|
182
|
+
|
|
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
|
+
---
|
|
195
|
+
## 🌍 Use Cases
|
|
196
|
+
* Digital signature of documents
|
|
197
|
+
* Smart contract interaction
|
|
198
|
+
* Federated profiles with trust anchors
|
|
199
|
+
* Group identity and shared contexts (`me && you && them in context/friends`)
|
|
200
|
+
|
|
201
|
+
---
|
|
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
|
+
|
|
61
205
|
<img src="https://suign.github.io/assets/imgs/monads.png" alt="Cleak Me Please" width="244">Hello, I am **.me**
|
|
206
|
+
|
|
62
207
|
### ❯ add.me
|
|
63
208
|
----
|
|
64
209
|
|
|
65
|
-
###### Using the CLI and this.me globally to manage user sessions.
|
|
66
|
-
```bash
|
|
67
|
-
npm i -g this.me
|
|
68
|
-
```
|
|
69
|
-
----------
|
|
70
|
-
|
|
71
210
|
# What is All.This?
|
|
72
|
-
|
|
73
211
|
###### Modular Data Structures:
|
|
74
|
-
|
|
75
212
|
**Each module** in **[all.this](https://neurons.me/all-this)** represents a specific **datastructure**. These **classes** encapsulate the functionalities and **data specific to their domain.**
|
|
76
213
|
|
|
77
214
|
**[this.me](https://docs.neurons.me/this.me/index.html) - [this.audio](https://docs.neurons.me/this.audio/index.html) - [this.text](https://docs.neurons.me/this.text/index.html) - [this.wallet](https://docs.neurons.me/this.wallet/index.html) - [this.img](https://docs.neurons.me/this.img/index.html) - [this.pixel](https://docs.neurons.me/this.pixel/index.html) - [be.this](https://docs.neurons.me/be.this/index.html) - [this.DOM](https://docs.neurons.me/this.DOM/index.html) - [this.env](https://docs.neurons.me/this.env/index.html) - [this.GUI](https://docs.neurons.me/this.GUI/index.html) - [this.be](https://docs.neurons.me/this.be/index.html) - [this.video](https://docs.neurons.me/this.video/index.html) - [this.dictionaries](https://docs.neurons.me/this.dictionaries/index.html)**
|
|
@@ -81,7 +218,7 @@ If you are interested in collaborating or wish to share your insights, please fe
|
|
|
81
218
|
|
|
82
219
|
#### License & Policies
|
|
83
220
|
- **License**: MIT License.
|
|
84
|
-
- **Learn more** at **https://
|
|
85
|
-
[Terms](https://
|
|
221
|
+
- **Learn more** at **https://neurons.me**
|
|
222
|
+
[Terms](https://neurons.me/terms-and-conditions) | [Privacy](https://neurons.me/privacy-policy)
|
|
86
223
|
|
|
87
224
|
<img src="https://docs.neurons.me/neurons.me.webp" alt="neurons.me logo" width="123" height="123">
|
package/bin/me.cli.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ./bin/me.cli.js
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import os from 'os';
|
|
9
|
+
import Me from '../src/me.js';
|
|
10
|
+
import { validateSetup } from '../src/scripts/setup_validation.js';
|
|
11
|
+
validateSetup(); // Asegura que ~/.this y ~/.this/me existen antes de usar el CLI
|
|
12
|
+
const program = new Command();
|
|
13
|
+
const ME_DIR = path.join(os.homedir(), '.this', 'me');
|
|
14
|
+
// Utilidad para obtener ruta de archivo `.me`
|
|
15
|
+
const getMeFilePath = (username) => path.join(ME_DIR, `${username}.me`);
|
|
16
|
+
program
|
|
17
|
+
.name('me')
|
|
18
|
+
.description('CLI to manage this.me identities')
|
|
19
|
+
.version('1.0.0');
|
|
20
|
+
// Comando: crear una identidad .me
|
|
21
|
+
program
|
|
22
|
+
.command('create')
|
|
23
|
+
.description('Create new .me identity')
|
|
24
|
+
.action(async () => {
|
|
25
|
+
const { username, hash } = await inquirer.prompt([
|
|
26
|
+
{
|
|
27
|
+
type: 'input',
|
|
28
|
+
name: 'username',
|
|
29
|
+
message: 'Enter a username:',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
type: 'password',
|
|
33
|
+
name: 'hash',
|
|
34
|
+
message: 'Define your hash (secret key):',
|
|
35
|
+
mask: '*',
|
|
36
|
+
}
|
|
37
|
+
]);
|
|
38
|
+
const mePath = getMeFilePath(username);
|
|
39
|
+
if (existsSync(mePath)) {
|
|
40
|
+
console.log(chalk.red(`❌ Identity '${username}' already exists.`));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const me = await Me.create(username, hash);
|
|
44
|
+
console.log(chalk.green(`✅ Identity '${me.username}' created and saved as ${mePath}`));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Command: show identity contents
|
|
48
|
+
program
|
|
49
|
+
.command('show')
|
|
50
|
+
.description('Show contents of a .me identity')
|
|
51
|
+
.argument('[username]', 'Username of the identity to show')
|
|
52
|
+
.action(async (usernameArg) => {
|
|
53
|
+
const { username, hash } = await inquirer.prompt([
|
|
54
|
+
{
|
|
55
|
+
type: 'input',
|
|
56
|
+
name: 'username',
|
|
57
|
+
message: 'Enter username to view:',
|
|
58
|
+
when: () => !usernameArg,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'password',
|
|
62
|
+
name: 'hash',
|
|
63
|
+
message: 'Enter your hash to unlock:',
|
|
64
|
+
mask: '*',
|
|
65
|
+
}
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
const finalUsername = usernameArg || username;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const me = await Me.load(finalUsername, hash);
|
|
72
|
+
console.log(chalk.cyan(`\n📂 Identity '${finalUsername}':\n`));
|
|
73
|
+
console.log(JSON.stringify(me, null, 2));
|
|
74
|
+
} catch (err) {
|
|
75
|
+
console.log(chalk.red(`Error: ${err.message}`));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Comando: listar identidades locales
|
|
80
|
+
program
|
|
81
|
+
.command('list')
|
|
82
|
+
.description('List available local .me identities')
|
|
83
|
+
.action(async () => {
|
|
84
|
+
const fs = await import('fs/promises');
|
|
85
|
+
fs.readdir(ME_DIR)
|
|
86
|
+
.then(files => {
|
|
87
|
+
const meFiles = files.filter(file => file.endsWith('.me'));
|
|
88
|
+
if (meFiles.length === 0) {
|
|
89
|
+
console.log(chalk.yellow('⚠️ No registered identities found.'));
|
|
90
|
+
} else {
|
|
91
|
+
console.log(chalk.cyan('📇 Available identities:'));
|
|
92
|
+
meFiles.forEach(file => console.log('•', file.replace('.me', '')));
|
|
93
|
+
console.log(chalk.gray('\nTip: Use `me show` or `me show <username>` to view identity contents.'));
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
.catch(err => console.log(chalk.red(`Error: ${err.message}`)));
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
program.parse(process.argv);
|
package/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
//index.js
|
|
1
|
+
// index.js
|
|
2
2
|
/**
|
|
3
3
|
* @module This.Me
|
|
4
4
|
* @description
|
|
5
5
|
* This.Me is a data-structured identity...
|
|
6
|
-
|
|
6
|
+
*/
|
|
7
7
|
|
|
8
|
+
import { validateSetup } from './src/scripts/setup_validation.js';
|
|
9
|
+
validateSetup(); // Asegura que ~/.this y ~/.this/me existen antes de continuar
|
|
8
10
|
import Me from './src/me.js';
|
|
9
|
-
//when a user declares "I am %.me," their digital existence is affirmed and recorded in the system.
|
|
10
|
-
export default Me;
|
|
11
|
+
// when a user declares "I am %.me," their digital existence is affirmed and recorded in the system.
|
|
12
|
+
export default Me;
|
package/jsdoc.json
CHANGED
|
File without changes
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
### **Index of `this.me` Structure**
|
|
2
|
+
Here’s a comprehensive list of the components and their purposes within the `this.me` class:
|
|
3
|
+
|
|
4
|
+
#### **1. Identity**
|
|
5
|
+
- **Description:** Immutable attributes defining the core identity of the user.
|
|
6
|
+
- Incluye claves criptográficas necesarias para autenticación, firma y encriptación.
|
|
7
|
+
#### **2. Attributes**
|
|
8
|
+
- **Description:** Flexible traits and descriptive properties of the user.
|
|
9
|
+
#### **3. Relationships**
|
|
10
|
+
- **Description:** Connections and associations with others.
|
|
11
|
+
#### **4. Reactions**
|
|
12
|
+
- **Description:** User’s interactions and engagements with the world.
|
|
13
|
+
#### **5. Properties**
|
|
14
|
+
- **Description:** Items owned or managed by the user.
|
|
15
|
+
|
|
16
|
+
------
|
|
17
|
+
|
|
18
|
+
### **1. The Me Structure Overview**
|
|
19
|
+
|
|
20
|
+
#### **Core Components**
|
|
21
|
+
- **Identity:** The foundation of the `this.me` object.
|
|
22
|
+
|
|
23
|
+
- Immutable attributes: `username`, `DID`, `publicKey`, `privateKey`.
|
|
24
|
+
- Core methods for validation, key generation, and secure signing.
|
|
25
|
+
|
|
26
|
+
- Example key storage:
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"username": "jabellae",
|
|
30
|
+
"DID": "did:cleaker:xyz123",
|
|
31
|
+
"publicKey": "abc123...",
|
|
32
|
+
"privateKey": "<encrypted or local-only>"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- Example method:
|
|
37
|
+
```js
|
|
38
|
+
jabellae.sign("message to sign"); // Returns signature using stored private key
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
- **Attributes:** Fundamental identity traits.
|
|
44
|
+
Store and manage user traits dynamically:
|
|
45
|
+
- Examples: Name, age, location, pronouns, bio.
|
|
46
|
+
**Use `.be()` to add or update attributes.**
|
|
47
|
+
Example:
|
|
48
|
+
```json
|
|
49
|
+
{ name: 'John Doe', age: 30, location: 'Earth' }
|
|
50
|
+
```
|
|
51
|
+
Implement `be()` as a flexible key-value store.
|
|
52
|
+
Add validation for specific attributes (if required).
|
|
53
|
+
|
|
54
|
+
--------
|
|
55
|
+
|
|
56
|
+
- **Relationships:** Connections with others.
|
|
57
|
+
- Examples: Friends, groups, networks, organizations.
|
|
58
|
+
**Contacts:** Individual connections.
|
|
59
|
+
**Groups:** Collections of users with shared context.
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
.relationships.addContact({ username: 'alice', status: 'friend' });
|
|
63
|
+
.relationships.createGroup({ name: 'Family', members: ['alice', 'bob'] });
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Define `addContact` and `createGroup` methods.
|
|
67
|
+
Enable nested relationship structures (e.g., groups of groups).
|
|
68
|
+
|
|
69
|
+
---------
|
|
70
|
+
|
|
71
|
+
- **Reactions:** How a user interacts with the world.
|
|
72
|
+
Streamline all user engagements under `.react()`
|
|
73
|
+
- Examples: Likes, comments, shares, emotions.
|
|
74
|
+
- Categorization Rationale:
|
|
75
|
+
- Keeps all engagements unified.
|
|
76
|
+
- Expands easily (adding emojis, advanced reactions).
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
.react.add({ type: 'like', target: 'PostID' });
|
|
80
|
+
.react.add({ type: 'comment', target: 'PhotoID', content: 'Great pic!' });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Design a structure to store and retrieve reactions efficiently.
|
|
84
|
+
Define a `log` system for reaction history.
|
|
85
|
+
|
|
86
|
+
-----
|
|
87
|
+
|
|
88
|
+
- **Properties:** Things the user owns or manages.
|
|
89
|
+
Attach external, modular objects as user-owned assets:
|
|
90
|
+
- Use `this.me.properties` as a unified interface for ownership.
|
|
91
|
+
- Modular objects like `Wallet`, `Device`, `File`.
|
|
92
|
+
- Examples: Wallets, devices, digital files, accounts.
|
|
93
|
+
- **Sub-Methods:** Add, Share, Transfer Ownership, Revoke Access.
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
const jabellae = new Me('jabellae'); // Create a new Me instance
|
|
97
|
+
const wallet = new Wallet({ type: 'ETH', address: '0x123...' }); // Create a wallet object
|
|
98
|
+
jabellae.addProperty(wallet); // Add wallet as a property to Me
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Implement `add`, `share`, `transferOwnership`, and `revokeAccess` methods for properties. Define modular objects (`Wallet`, `Device`) independently.
|
|
102
|
+
|
|
103
|
+
1. **Creating a Wallet**
|
|
104
|
+
The wallet is created independently and then added to the `Me` instance's properties.
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
const jabellae = new Me('jabellae'); // Create a new Me instance
|
|
108
|
+
const wallet = new Wallet({ type: 'ETH', address: '0x123...' }); // Create a wallet object
|
|
109
|
+
jabellae.addProperty(wallet); // Add wallet as a property to Me
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
2. **Sharing the Wallet**
|
|
113
|
+
Sharing logic is handled by the `Me` instance, not the property itself.
|
|
114
|
+
|
|
115
|
+
```javascript
|
|
116
|
+
jabellae.shareProperty(wallet, 'otherMe', { permissions: 'view' });
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
3. **Transferring Ownership**
|
|
120
|
+
Ownership transfer is also managed by the `Me` instance.
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
jabellae.transferOwnership(wallet, 'otherMe');
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
------
|
|
127
|
+
|
|
128
|
+
### **2. Why Independent Objects?**
|
|
129
|
+
|
|
130
|
+
#### **Modularity**
|
|
131
|
+
- Keeps the `this.me` instance *agnostic* of specifics.
|
|
132
|
+
- Allows new property types to integrate seamlessly.
|
|
133
|
+
|
|
134
|
+
#### **Reusability**
|
|
135
|
+
- Each property (e.g., `this.wallet`, `this.device`) operates independently.
|
|
136
|
+
- Can be ported across `this.me` instances without coupling.
|
|
137
|
+
|
|
138
|
+
#### **Transferability**
|
|
139
|
+
- Ownership is a property-level concern.
|
|
140
|
+
- Example:
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
const wallet = new Wallet(owner = "me");
|
|
144
|
+
wallet.transferOwnership("otherMeInstance");
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### **Separation of Concerns**
|
|
148
|
+
- Identity (`this.me`) manages relationships, attributes, and higher-level user interactions.
|
|
149
|
+
- Objects like `Wallet` or `Device` manage their specific functionality.
|
|
150
|
+
|
|
151
|
+
#### **Scalability**
|
|
152
|
+
- Adding a new property type is as simple as:
|
|
153
|
+
1. Defining the object (e.g., `Vehicle`).
|
|
154
|
+
2. Registering it with `this.me`.
|
package/notes/Index.md
CHANGED
|
File without changes
|
|
File without changes
|
package/notes/Questions.md
CHANGED
|
File without changes
|
package/notes/Summary.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# this.me — Identity System
|
|
2
|
+
|
|
3
|
+
## ✨ Summary
|
|
4
|
+
`this.me` is a decentralized identity system designed to allow users to manage their own identities locally, with optional validation by external authorities such as Cleaker. It combines privacy, user control, and secure interoperability.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## 🔐 Identity Model Comparison
|
|
8
|
+
| **Model** | **Where your identity lives** | **Local signing** | **Real freedom** |
|
|
9
|
+
|----------------------|-------------------------------|-------------------|--------------------------|
|
|
10
|
+
| Web2 (Facebook, etc) | On their servers | ❌ | ❌ |
|
|
11
|
+
| Web3 (wallets) | In extensions or apps | ✅ | 🟡 (fragmented) |
|
|
12
|
+
| `this.me` | In your OS `.this/me/` | ✅✅ | ✅✅✅ |
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 🔍 Core Principles
|
|
17
|
+
1. **Freedom to Declare**
|
|
18
|
+
Anyone can generate a `.me` identity locally without external approval.
|
|
19
|
+
2. **Trusted Endorsements**
|
|
20
|
+
Authorities (e.g., Cleaker) can endorse `.me` identities without controlling them.
|
|
21
|
+
3. **Local Ownership**
|
|
22
|
+
All sensitive data (including private keys) stays on the user's machine.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
## 📁 File Structure
|
|
26
|
+
* `~/.this/me/username.me.json` — Encrypted identity file
|
|
27
|
+
* `.me` includes:
|
|
28
|
+
|
|
29
|
+
* `username`
|
|
30
|
+
* `publicKey`, `privateKey` (encrypted)
|
|
31
|
+
* `attributes`, `relationships`, `reactions`, `properties`, `relationships`
|
|
32
|
+
* `endorsements`
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 🔎 Identity Lifecycle
|
|
37
|
+
|
|
38
|
+
### 1. Create Identity
|
|
39
|
+
```bash
|
|
40
|
+
me create jabellae
|
|
41
|
+
# Prompts for hash (e.g. 4242)
|
|
42
|
+
# Generates encrypted .me file
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Register/Endorse with Authority
|
|
46
|
+
```bash
|
|
47
|
+
me endorse --with cleaker
|
|
48
|
+
# Signs and shares publicKey with Cleaker
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 3. Verify Identity
|
|
52
|
+
```bash
|
|
53
|
+
me verify --with cleaker
|
|
54
|
+
# Validates signature and authority endorsement
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 4. Migrate Across Devices
|
|
58
|
+
```bash
|
|
59
|
+
me restore --from-seed
|
|
60
|
+
# Or use encrypted backup file + hash
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 5. Rotate Keys
|
|
64
|
+
```bash
|
|
65
|
+
me rotate
|
|
66
|
+
# Generates new key pair, requires re-endorsement
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 🔐 Cryptographic Model
|
|
72
|
+
* Identity is unlocked using a user-defined `hash` (password).
|
|
73
|
+
* This hash decrypts the local `.me` file.
|
|
74
|
+
* The identity includes:
|
|
75
|
+
|
|
76
|
+
* A **key pair** (public/private) for signing and verification.
|
|
77
|
+
* Optional **endorsements** signed by Cleaker or other authorities.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 🛡️ Security Model
|
|
82
|
+
* No private key ever leaves the local `.me` file.
|
|
83
|
+
* Endorsements are public and verifiable using the public key.
|
|
84
|
+
* If compromised, user can rotate keys and notify authorities.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 🌐 Multi-Device Support
|
|
89
|
+
* `.me` can be restored using a seed phrase or backup.
|
|
90
|
+
* New devices can be authorized using signatures from old devices.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## ⚖️ Responsibilities
|
|
95
|
+
|
|
96
|
+
* **this.me**
|
|
97
|
+
* Local file management, encryption, signing.
|
|
98
|
+
* CLI + API for usage.
|
|
99
|
+
|
|
100
|
+
* **Cleaker / Authorities**
|
|
101
|
+
|
|
102
|
+
* Store trusted records of `username` + `publicKey`
|
|
103
|
+
* Provide validation/endorsement services.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 🌍 Future Use Cases
|
|
108
|
+
* Digital signature of documents
|
|
109
|
+
* Smart contract interaction
|
|
110
|
+
* Federated profiles with trust anchors
|
|
111
|
+
* Group identity and shared contexts (`me && you && them in context/friends`)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 📖 Glossary
|
|
116
|
+
* `hash`: A password-like string used to unlock `.me`
|
|
117
|
+
* `endorsement`: Signature from a recognized authority on the identity
|
|
118
|
+
* `publicKey/privateKey`: Cryptographic key pair for identity signing
|
|
119
|
+
* `Cleaker`: Example identity authority ledger
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
**Author:** suiGn / neurons.me
|
|
124
|
+
**License:** MIT
|
|
125
|
+
**Project:** [this.me](https://www.npmjs.com/package/this.me)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
The Problem: Decentralized Yet Trustworthy
|
|
2
|
+
Identity, by its nature, is both personal and relational. On the one hand, we want the freedom to define ourselves without external constraints. On the other, our identities must often be validated by trusted authorities to engage in meaningful transactions, whether signing a digital contract or interacting with a service.
|
|
3
|
+
|
|
4
|
+
Traditional centralized systems — such as social media platforms, government IDs, or corporate logins — often prioritize control over freedom. These systems require users to surrender their data and identities to be recognized. While decentralized technologies like blockchains have emerged to challenge this model, they introduce their own complexities and limitations, such as over-reliance on cryptographic keys or lack of intuitive identity frameworks.
|
|
5
|
+
|
|
6
|
+
The question arises:How can we create an identity system that respects personal sovereignty while ensuring trust and usability in a networked world?
|
|
7
|
+
|
|
8
|
+
Enter This.me: A New Paradigm for Identity
|
|
9
|
+
This.me offers a framework for identity creation and interaction that revolves around two core principles:
|
|
10
|
+
|
|
11
|
+
1. Freedom to Declare: Anyone can create a `.me` instance and define their identity without external permissions. This identity exists as a standalone object, enabling users to interact in a purely self-declared state.
|
|
12
|
+
|
|
13
|
+
2. Trust Anchors: When needed, central authorities or networks, such as Cleaker, can validate the identity. These authorities provide the infrastructure for authentication, signing, and verification without compromising the user’s control over their identity.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
This structure implies:
|
|
2
|
+
|
|
3
|
+
1. Logical Grouping of Entities: me && you && him represents a logical grouping, where each entity is included as part of a broader relationship.
|
|
4
|
+
|
|
5
|
+
2. Contextual Scoping: Context/mexicans provides a scope within which this relationship exists, giving meaning to the relationship without establishing a strict hierarchy among me, you, and him.
|
|
6
|
+
|
|
7
|
+
3. Dynamic Meaning: The meaning can change based on context. For example:
|
|
8
|
+
|
|
9
|
+
• me && you && himContext/mexicans could mean a group of entities (me, you, him) sharing a “Mexican” attribute.
|
|
10
|
+
|
|
11
|
+
Context/friends might represent the same group within a “friends” context, applying different attributes or significance.
|
package/notes/hot_encoding.md
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "this.me",
|
|
3
|
-
"version": "2.9.
|
|
3
|
+
"version": "2.9.51",
|
|
4
4
|
"description": "_me-Centric.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "node index.js",
|
|
8
|
-
"test": "test"
|
|
8
|
+
"test": "test",
|
|
9
|
+
"postinstall": "node src/scripts/setup.js"
|
|
9
10
|
},
|
|
10
11
|
"bin": {
|
|
11
|
-
"
|
|
12
|
+
"me": "bin/me.cli.js"
|
|
12
13
|
},
|
|
13
14
|
"keywords": [
|
|
14
15
|
"this.me",
|
package/src/example.js
CHANGED
|
File without changes
|
package/src/me.js
CHANGED
|
@@ -1,53 +1,147 @@
|
|
|
1
|
-
//
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
1
|
+
// src/me.js
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import crypto from 'crypto';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
|
|
7
|
+
const ROOT_DIR = path.join(os.homedir(), '.this', 'me');
|
|
9
8
|
|
|
9
|
+
class Me {
|
|
10
|
+
constructor(username) {
|
|
10
11
|
this.username = username;
|
|
11
|
-
this.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
this.filePath = path.join(ROOT_DIR, `${username}.me`); // encrypted .me file path
|
|
13
|
+
this.unlocked = false; // will become true after decrypting with correct hash
|
|
14
|
+
this.data = null; // holds decrypted data (identity, keys, attributes, etc.)
|
|
15
|
+
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Encrypt and write the current `this.data` to disk.
|
|
19
|
+
*/
|
|
20
|
+
save(hash) {
|
|
21
|
+
if (!this.data) throw new Error('No data to save');
|
|
22
|
+
const iv = crypto.randomBytes(16);
|
|
23
|
+
const key = crypto.createHash('sha256').update(hash).digest();
|
|
24
|
+
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
|
|
25
|
+
const encrypted = Buffer.concat([
|
|
26
|
+
iv,
|
|
27
|
+
cipher.update(JSON.stringify(this.data)),
|
|
28
|
+
cipher.final()
|
|
29
|
+
]);
|
|
30
|
+
fs.writeFileSync(this.filePath, encrypted);
|
|
19
31
|
}
|
|
20
32
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Unlock the .me file by decrypting it using the provided hash.
|
|
35
|
+
*/
|
|
36
|
+
unlock(hash) {
|
|
37
|
+
const fileBuffer = fs.readFileSync(this.filePath);
|
|
38
|
+
const iv = fileBuffer.slice(0, 16);
|
|
39
|
+
const encryptedData = fileBuffer.slice(16);
|
|
40
|
+
const key = crypto.createHash('sha256').update(hash).digest();
|
|
41
|
+
try {
|
|
42
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
|
|
43
|
+
const decrypted = Buffer.concat([
|
|
44
|
+
decipher.update(encryptedData),
|
|
45
|
+
decipher.final()
|
|
46
|
+
]);
|
|
47
|
+
this.data = JSON.parse(decrypted.toString('utf-8'));
|
|
48
|
+
this.unlocked = true;
|
|
49
|
+
return true;
|
|
50
|
+
} catch (err) {
|
|
51
|
+
return false; // incorrect hash or corrupted file
|
|
24
52
|
}
|
|
25
|
-
return new Me(username, Me.registry[username]);
|
|
26
53
|
}
|
|
27
54
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Locks the session by wiping in-memory data.
|
|
57
|
+
*/
|
|
58
|
+
lock() {
|
|
59
|
+
this.data = null;
|
|
60
|
+
this.unlocked = false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Create a new identity file for the given username.
|
|
65
|
+
* Called only if it doesn't already exist.
|
|
66
|
+
*/
|
|
67
|
+
static create(username, hash) {
|
|
68
|
+
const me = new Me(username);
|
|
69
|
+
if (fs.existsSync(me.filePath)) {
|
|
70
|
+
throw new Error('Identity already exists');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Generate keys or initial structure
|
|
74
|
+
me.data = {
|
|
75
|
+
identity: {
|
|
76
|
+
username,
|
|
77
|
+
publicKey: 'publicKeyPlaceholder', // later generate real keypair
|
|
78
|
+
privateKey: 'privateKeyPlaceholder'
|
|
79
|
+
},
|
|
80
|
+
attributes: {},
|
|
81
|
+
relationships: [],
|
|
82
|
+
reactions: [],
|
|
83
|
+
endorsements: []
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
me.save(hash);
|
|
87
|
+
return me;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create a new identity file for the given username.
|
|
92
|
+
* Called only if it doesn't already exist.
|
|
93
|
+
*/
|
|
94
|
+
static create(username, hash) {
|
|
95
|
+
const me = new Me(username);
|
|
96
|
+
if (fs.existsSync(me.filePath)) {
|
|
97
|
+
throw new Error('Identity already exists');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Generate keys or initial structure
|
|
101
|
+
me.data = {
|
|
102
|
+
identity: {
|
|
103
|
+
username,
|
|
104
|
+
publicKey: 'publicKeyPlaceholder', // later generate real keypair
|
|
105
|
+
privateKey: 'privateKeyPlaceholder'
|
|
106
|
+
},
|
|
107
|
+
attributes: {},
|
|
108
|
+
relationships: [],
|
|
109
|
+
reactions: [],
|
|
110
|
+
endorsements: []
|
|
34
111
|
};
|
|
35
112
|
|
|
36
|
-
|
|
37
|
-
|
|
113
|
+
me.save(hash);
|
|
114
|
+
return me;
|
|
38
115
|
}
|
|
39
116
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Load and decrypt an existing identity.
|
|
119
|
+
*/
|
|
120
|
+
static load(username, hash) {
|
|
121
|
+
const me = new Me(username);
|
|
122
|
+
const success = me.unlock(hash);
|
|
123
|
+
if (!success) throw new Error('Invalid hash or corrupted file');
|
|
124
|
+
return me;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Add an endorsement (external signature asserting trust in this identity).
|
|
128
|
+
*/
|
|
129
|
+
addEndorsement(endorsement) {
|
|
130
|
+
if (!this.unlocked) throw new Error('Identity is locked');
|
|
131
|
+
this.data.endorsements.push(endorsement);
|
|
43
132
|
}
|
|
44
133
|
|
|
45
|
-
|
|
46
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Example: add an attribute to this.me (like `.be("artist")`).
|
|
136
|
+
*/
|
|
137
|
+
be(key, value) {
|
|
138
|
+
if (!this.unlocked) throw new Error('Identity is locked');
|
|
139
|
+
this.data.attributes[key] = value;
|
|
47
140
|
}
|
|
48
141
|
|
|
49
|
-
|
|
50
|
-
|
|
142
|
+
getAttributes() {
|
|
143
|
+
if (!this.unlocked) throw new Error('Identity is locked');
|
|
144
|
+
return this.data.attributes;
|
|
51
145
|
}
|
|
52
146
|
}
|
|
53
147
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Attributes methods
|
|
2
|
+
/**
|
|
3
|
+
* @module Attributes
|
|
4
|
+
* @description Methods to manage attributes for the `Me` class, with key-vaue pairs.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* @description Adds or updates an attribute for the `me` instance.
|
|
8
|
+
*
|
|
9
|
+
* This method allows you to dynamically add or update descriptive attributes
|
|
10
|
+
* for the `me` instance. Attributes are stored as key-value pairs, where:
|
|
11
|
+
* - The **key** represents the name of the attribute (e.g., "name", "age", "location").
|
|
12
|
+
* - The **value** represents the data associated with that attribute (e.g., "Sui Gn", 30, "Earth").
|
|
13
|
+
*
|
|
14
|
+
* You can add as many key-value pairs as you want, giving you the flexibility to describe
|
|
15
|
+
* the `me` instance with plain data. The attributes are stored in an object, and each call
|
|
16
|
+
* to `be` either adds a new attribute or updates an existing one if the key already exists.
|
|
17
|
+
*
|
|
18
|
+
* This approach ensures that the `me` instance can evolve and be customized over time
|
|
19
|
+
* with additional or modified attributes as needed.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} key - The attribute key (e.g., "name").
|
|
22
|
+
* @param {string|number|boolean|Object} value - The attribute value associated with the key.
|
|
23
|
+
* This can be any data type (e.g., string, number, boolean, or even a nested object).
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Adding a single attribute
|
|
27
|
+
* me.be("name", "Sui Gn");
|
|
28
|
+
* console.log(me.getAttributes()); // { name: "Sui Gn" }
|
|
29
|
+
*
|
|
30
|
+
* // Adding multiple attributes
|
|
31
|
+
* me.be("age", 30);
|
|
32
|
+
* me.be("location", "Earth");
|
|
33
|
+
* console.log(me.getAttributes());
|
|
34
|
+
* // Output: { name: "Sui Gn", age: 30, location: "Earth" }
|
|
35
|
+
*
|
|
36
|
+
* // Updating an existing attribute
|
|
37
|
+
* me.be("name", "John Doe");
|
|
38
|
+
* console.log(me.getAttributes());
|
|
39
|
+
* // Output: { name: "John Doe", age: 30, location: "Earth" }
|
|
40
|
+
*
|
|
41
|
+
* // Using complex data types
|
|
42
|
+
* me.be("preferences", { theme: "dark", language: "en" });
|
|
43
|
+
* console.log(me.getAttributes());
|
|
44
|
+
* // Output: { name: "John Doe", age: 30, location: "Earth", preferences: { theme: "dark", language: "en" } }
|
|
45
|
+
*/
|
|
46
|
+
export function be(attributes, key, value) {
|
|
47
|
+
if (!key || typeof key !== 'string') {
|
|
48
|
+
throw new Error('Invalid key for attribute');
|
|
49
|
+
}
|
|
50
|
+
attributes[key] = value;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @description Retrieves all attributes associated with the `me` instance.
|
|
54
|
+
*
|
|
55
|
+
* This method provides access to the current set of attributes stored in the `me` instance
|
|
56
|
+
* as an object containing key-value pairs. Each key represents the name of an attribute,
|
|
57
|
+
* and its corresponding value represents the data stored for that attribute.
|
|
58
|
+
*
|
|
59
|
+
* You can either:
|
|
60
|
+
* - Retrieve all attributes at once as a single object.
|
|
61
|
+
* - Access specific attributes directly using their keys.
|
|
62
|
+
*
|
|
63
|
+
* @returns {Object} An object containing all the key-value pairs representing
|
|
64
|
+
* the attributes of the `me` instance.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Retrieving all attributes
|
|
68
|
+
* console.log(me.getAttributes());
|
|
69
|
+
* // Output: { name: "Sui Gn", age: 30, location: "Earth" }
|
|
70
|
+
*
|
|
71
|
+
* // Accessing specific attributes by their key
|
|
72
|
+
* const attributes = me.getAttributes();
|
|
73
|
+
* console.log(attributes.name); // "Sui Gn"
|
|
74
|
+
* console.log(attributes.age); // 30
|
|
75
|
+
* console.log(attributes.location); // "Earth"
|
|
76
|
+
*/
|
|
77
|
+
export function getAttributes(attributes) {
|
|
78
|
+
return attributes;
|
|
79
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Identity
|
|
3
|
+
* @description Methods to manage identity for the `Me` class.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Sets up the identity for a `Me` instance.
|
|
8
|
+
* @function
|
|
9
|
+
* @param {string} username - The username to set for the identity.
|
|
10
|
+
* @returns {Object} The identity object containing the username.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const identity = setup("suiGn");
|
|
14
|
+
* console.log(identity); // { username: "suiGn" }
|
|
15
|
+
*/
|
|
16
|
+
export function setup(username) {
|
|
17
|
+
return { username };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Retrieves the username (identity) of the `Me` instance.
|
|
22
|
+
* @function
|
|
23
|
+
* @param {Object} identity - The identity object of the `Me` instance.
|
|
24
|
+
* @returns {Object} The `Me` username identity object.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* console.log(getMe({ username: "suiGn" })); // { username: "suiGn" }
|
|
28
|
+
*/
|
|
29
|
+
export function getMe(identity) {
|
|
30
|
+
return identity;
|
|
31
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// this.me/src/methods/properties.js
|
|
2
|
+
/**
|
|
3
|
+
* @module Properties
|
|
4
|
+
* @description Methods to manage properties for the `Me` class.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validates a property before adding it.
|
|
9
|
+
* @function
|
|
10
|
+
* @param {Object} property - The property to validate.
|
|
11
|
+
* @throws {Error} If the property is invalid.
|
|
12
|
+
*/
|
|
13
|
+
function validateProperty(property) {
|
|
14
|
+
if (!property || typeof property !== 'object') {
|
|
15
|
+
throw new Error('Invalid property: Must be a non-null object.');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Adds a property to the identity.
|
|
21
|
+
* @function
|
|
22
|
+
* @param {Array} properties - The properties array to update.
|
|
23
|
+
* @param {Object} property - The property to add (e.g., { type: "ETH", address: "0x123..." }).
|
|
24
|
+
*/
|
|
25
|
+
function addProperty(properties, property) {
|
|
26
|
+
validateProperty(property);
|
|
27
|
+
properties.push(property);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Retrieves all properties for the identity.
|
|
32
|
+
* @function
|
|
33
|
+
* @param {Array} properties - The properties array to retrieve from.
|
|
34
|
+
* @returns {Array} The properties array.
|
|
35
|
+
*/
|
|
36
|
+
function getProperties(properties) {
|
|
37
|
+
return [...properties]; // Return a shallow copy to prevent mutation outside
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Removes a property from the identity.
|
|
42
|
+
* @function
|
|
43
|
+
* @param {Array} properties - The properties array to update.
|
|
44
|
+
* @param {Object} property - The property to remove.
|
|
45
|
+
*/
|
|
46
|
+
function removeProperty(properties, property) {
|
|
47
|
+
validateProperty(property);
|
|
48
|
+
const index = properties.findIndex(p => JSON.stringify(p) === JSON.stringify(property));
|
|
49
|
+
if (index !== -1) properties.splice(index, 1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Checks if a specific property exists.
|
|
54
|
+
* @function
|
|
55
|
+
* @param {Array} properties - The properties array.
|
|
56
|
+
* @param {Object} property - The property to check.
|
|
57
|
+
* @returns {boolean} True if the property exists, otherwise false.
|
|
58
|
+
*/
|
|
59
|
+
function hasProperty(properties, property) {
|
|
60
|
+
validateProperty(property);
|
|
61
|
+
return properties.some(p => JSON.stringify(p) === JSON.stringify(property));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Named exports
|
|
65
|
+
export { addProperty, getProperties, removeProperty, hasProperty };
|
|
66
|
+
|
|
67
|
+
// Default export (optional for easier import as an object)
|
|
68
|
+
export default {
|
|
69
|
+
addProperty,
|
|
70
|
+
getProperties,
|
|
71
|
+
removeProperty,
|
|
72
|
+
hasProperty
|
|
73
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//this.me/src/methods/reactions.js
|
|
2
|
+
/**
|
|
3
|
+
* @module Reactions
|
|
4
|
+
* @description Methods to manage reactions for the `Me` class.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Add a reaction to a target.
|
|
8
|
+
* @function
|
|
9
|
+
* @param {Array} reactions - The reactions array to update.
|
|
10
|
+
* @param {string} type - The type of reaction (e.g., "like", "comment").
|
|
11
|
+
* @param {string} target - The target of the reaction (e.g., "PostID").
|
|
12
|
+
* @param {string} [content=null] - Additional content for the reaction (e.g., a comment).
|
|
13
|
+
* @throws {Error} If the type or target is invalid.
|
|
14
|
+
*/
|
|
15
|
+
export function react(reactions, type, target, content = null) {
|
|
16
|
+
if (!type || !target) {
|
|
17
|
+
throw new Error('Invalid reaction parameters');
|
|
18
|
+
}
|
|
19
|
+
reactions.push({ type, target, content, timestamp: new Date() });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Retrieve all reactions for the identity.
|
|
24
|
+
* @function
|
|
25
|
+
* @param {Array} reactions - The reactions array to retrieve from.
|
|
26
|
+
* @returns {Array} The reactions array.
|
|
27
|
+
* @instance
|
|
28
|
+
*/
|
|
29
|
+
export function getReactions(reactions) {
|
|
30
|
+
return reactions;
|
|
31
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Relationships
|
|
3
|
+
* @description Manages user relationships.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Function to add a relationship
|
|
7
|
+
export function addRelationship(relationships, relationship) {
|
|
8
|
+
if (!relationship || !relationship.type || !relationship.username) {
|
|
9
|
+
throw new Error('Invalid relationship object. Must include type and username.');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
relationships.push(relationship);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Function to retrieve relationships
|
|
16
|
+
export function getRelationships(relationships, type = null) {
|
|
17
|
+
if (type) {
|
|
18
|
+
return relationships.filter(rel => rel.type === type);
|
|
19
|
+
}
|
|
20
|
+
return relationships;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Function to initialize relationships for a user
|
|
24
|
+
export function createRelationships() {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// setup.js
|
|
2
|
+
import { mkdirSync, existsSync } from 'fs';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
const root = path.join(homedir(), '.this');
|
|
6
|
+
const mePath = path.join(root, 'me');
|
|
7
|
+
if (!existsSync(root)) {
|
|
8
|
+
mkdirSync(root);
|
|
9
|
+
console.log('✅ Created ~/.this root directory');
|
|
10
|
+
} else {
|
|
11
|
+
console.log('✅ ~/.this root directory already exists');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (!existsSync(mePath)) {
|
|
15
|
+
mkdirSync(mePath);
|
|
16
|
+
console.log('✅ Created ~/.this/me directory');
|
|
17
|
+
} else {
|
|
18
|
+
console.log('✅ ~/.this/me directory already exists');
|
|
19
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
const root = path.join(homedir(), '.this');
|
|
6
|
+
const mePath = path.join(root, 'me');
|
|
7
|
+
|
|
8
|
+
export function validateSetup() {
|
|
9
|
+
let updated = false;
|
|
10
|
+
|
|
11
|
+
if (!existsSync(root)) {
|
|
12
|
+
mkdirSync(root);
|
|
13
|
+
console.log('✅ Created ~/.this root directory');
|
|
14
|
+
updated = true;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!existsSync(mePath)) {
|
|
18
|
+
mkdirSync(mePath);
|
|
19
|
+
console.log('✅ Created ~/.this/me directory');
|
|
20
|
+
updated = true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!updated) {
|
|
24
|
+
console.log('.me >> init.');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Run directly if script is executed as entry point
|
|
29
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
30
|
+
validateSetup();
|
|
31
|
+
}
|
package/src/.me.cli.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
//.me.cli.js
|
|
3
|
-
import { program } from 'commander';
|
|
4
|
-
import { meMainChoices } from './CLI/me_MainChoices.js';
|
|
5
|
-
import AddMe from './CLI/AddMe.js';
|
|
6
|
-
import LogMe from './CLI/LogMe.js';
|
|
7
|
-
program
|
|
8
|
-
.description('.Me Command Line Interface')
|
|
9
|
-
.version('1.0.0')
|
|
10
|
-
.action(meMainChoices);
|
|
11
|
-
|
|
12
|
-
program.command('add-me')
|
|
13
|
-
.description('+ Add .me')
|
|
14
|
-
.action(AddMe);
|
|
15
|
-
|
|
16
|
-
program.command('log-me')
|
|
17
|
-
.description('Log .me')
|
|
18
|
-
.action(LogMe);
|
|
19
|
-
|
|
20
|
-
program.parse(process.argv);
|