holosphere 1.0.4 → 1.0.6
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/holosphere.d.ts +22 -0
- package/{index.js → holosphere.js} +221 -189
- package/package.json +2 -2
package/holosphere.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
declare module 'holosphere' {
|
|
2
|
+
export default class HoloSphere {
|
|
3
|
+
constructor(name: string, openaikey?: string | null);
|
|
4
|
+
subscribe(hex: string, lense: string, callback: (item: any, key: string) => void): void;
|
|
5
|
+
put(hex: string, lense: string, content: any): Promise<void>;
|
|
6
|
+
delete(id: string, tag: string): Promise<void>;
|
|
7
|
+
get(hex: string, lense: string): Promise<any[]>;
|
|
8
|
+
getKey(hex: string, lense: string, key: string): Promise<any | null>;
|
|
9
|
+
getNode(hex: string, lense: string, key: string): Promise<any | null>;
|
|
10
|
+
compute(hex: string, lense: string, operation: string): Promise<void>;
|
|
11
|
+
clearlense(hex: string, lense: string): Promise<void>;
|
|
12
|
+
summarize(history: string): Promise<string>;
|
|
13
|
+
upcast(hex: string, lense: string, content: any): Promise<any>;
|
|
14
|
+
updateParent(id: string, report: string): Promise<any>;
|
|
15
|
+
getHex(lat: number, lng: number, resolution: number): Promise<string>;
|
|
16
|
+
getScalespace(lat: number, lng: number): string[];
|
|
17
|
+
getHexScalespace(hex: string): string[];
|
|
18
|
+
aggregateVotes(hexId: string, topic: string): object;
|
|
19
|
+
delegateVote(userId: string, topic: string, delegateTo: string): Promise<void>;
|
|
20
|
+
vote(userId: string, hexId: string, topic: string, vote: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -4,10 +4,15 @@ import Gun from 'gun'
|
|
|
4
4
|
import Ajv2019 from 'ajv/dist/2019.js'
|
|
5
5
|
|
|
6
6
|
class HoloSphere {
|
|
7
|
+
/**
|
|
8
|
+
* Initializes a new instance of the HoloSphere class.
|
|
9
|
+
* @param {string} appname - The name of the application.
|
|
10
|
+
* @param {string|null} openaikey - The OpenAI API key.
|
|
11
|
+
*/
|
|
7
12
|
constructor(appname, openaikey = null) {
|
|
8
13
|
this.validator = new Ajv2019({ allErrors: false, strict: false });
|
|
9
14
|
this.gun = Gun({
|
|
10
|
-
peers: ['
|
|
15
|
+
peers: ['https://59.src.eco/gun'],
|
|
11
16
|
axe: false,
|
|
12
17
|
// uuid: (content) => { // generate a unique id for each node
|
|
13
18
|
// console.log('uuid', content);
|
|
@@ -15,119 +20,22 @@ class HoloSphere {
|
|
|
15
20
|
});
|
|
16
21
|
|
|
17
22
|
this.gun = this.gun.get(appname)
|
|
23
|
+
this.users = {}; // Initialize users
|
|
24
|
+
this.hexagonVotes = {}; // Initialize hexagonVotes
|
|
18
25
|
|
|
19
26
|
if (openaikey != null) {
|
|
20
27
|
this.openai = new OpenAI({
|
|
21
28
|
apiKey: openaikey,
|
|
22
29
|
});
|
|
23
30
|
}
|
|
24
|
-
|
|
25
|
-
//this.bot.command('sethex', async (ctx) => { this.setHex(ctx) }) TODO: MOVE HERE FROM SETTINGS
|
|
26
|
-
|
|
27
|
-
// this.bot.command('resethex', async (ctx) => {
|
|
28
|
-
// let chatID = ctx.message.chat.id;
|
|
29
|
-
// let hex = (await this.db.get('settings', chatID)).hex
|
|
30
|
-
// this.delete(hex, ctx.message.text.split(' ')[1])
|
|
31
|
-
// })
|
|
32
|
-
|
|
33
|
-
// this.bot.command('get', async (ctx) => {
|
|
34
|
-
// const chatID = ctx.message.chat.id;
|
|
35
|
-
// const lense = ctx.message.text.split(' ')[1];
|
|
36
|
-
// if (!lense) {
|
|
37
|
-
// return ctx.reply('Please specify a tag.');
|
|
38
|
-
// }
|
|
39
|
-
// let hex = (await this.db.get('settings', chatID)).hex
|
|
40
|
-
// //let hex = settings.hex
|
|
41
|
-
// console.log('hex', hex)
|
|
42
|
-
|
|
43
|
-
// let data = await this.get(ctx, hex, lense)
|
|
44
|
-
|
|
45
|
-
// })
|
|
46
|
-
|
|
47
|
-
// this.bot.command('gethex', async (ctx) => {
|
|
48
|
-
// let settings = await this.db.get('settings', chatID)
|
|
49
|
-
// let id = settings.hex ? settings.hex : 'Hex not set, use /sethex'
|
|
50
|
-
// ctx.reply(id)
|
|
51
|
-
// })
|
|
52
|
-
|
|
53
|
-
// this.bot.command('compute', async (ctx) => {
|
|
54
|
-
// const chatID = ctx.message.chat.id;
|
|
55
|
-
// let operation = ctx.message.text.split(' ')[1];
|
|
56
|
-
// if (operation != 'sum') {
|
|
57
|
-
// ctx.reply('Operation not implemented')
|
|
58
|
-
// return
|
|
59
|
-
// }
|
|
60
|
-
// let lense = ctx.message.text.split(' ')[2]
|
|
61
|
-
// if (!lense) {
|
|
62
|
-
// ctx.reply('Please specify a lense where to perform the operation ')
|
|
63
|
-
// return
|
|
64
|
-
// }
|
|
65
|
-
// let hex = (await this.db.get('settings', chatID)).hex
|
|
66
|
-
// await this.compute(hex, lense, operation)
|
|
67
|
-
|
|
68
|
-
// // let parentInfo = await this.getCellInfo(parent)
|
|
69
|
-
// // parentInfo.wisdom[id] = report
|
|
70
|
-
// // //update summary
|
|
71
|
-
// // let summary = await this.summarize(Object.values(parentInfo.wisdom).join('\n'))
|
|
72
|
-
// // parentInfo.summary = summary
|
|
73
|
-
|
|
74
|
-
// // await this.db.put('cell', parentInfo)
|
|
75
|
-
// // return parentInfo
|
|
76
|
-
|
|
77
|
-
// // let content = await this.db.getAll(hex+'/tags')
|
|
78
|
-
// })
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// this.bot.command('cast', async (ctx) => {
|
|
84
|
-
// if (!ctx.message.reply_to_message) {
|
|
85
|
-
// return ctx.reply('Please reply to a message you want to tag.');
|
|
86
|
-
// }
|
|
87
|
-
// const tags = ctx.message.text.split(' ').slice(1);
|
|
88
|
-
// if (tags.length === 0) {
|
|
89
|
-
// return ctx.reply('Please provide at least one tag.');
|
|
90
|
-
// }
|
|
91
|
-
|
|
92
|
-
// const messageID = ctx.message.reply_to_message.message_id;
|
|
93
|
-
// const chatID = ctx.message.chat.id;
|
|
94
|
-
// const messageContent = ctx.message.reply_to_message.text;
|
|
95
|
-
// let settings = await this.db.get('settings', chatID)
|
|
96
|
-
// let id = settings.hex ? settings.hex : 'Hex not set, use /sethex'
|
|
97
|
-
// //create root node for the item
|
|
98
|
-
// let node = await this.gun.get(chatID + '/' + messageID).put({ id: chatID + '/' + messageID, content: messageContent })
|
|
99
|
-
// for (let tag of tags) {
|
|
100
|
-
// await this.gun.get(id).get(tag).set(node)
|
|
101
|
-
// this.upcast(id, tag, node)
|
|
102
|
-
// }
|
|
103
|
-
// })
|
|
104
|
-
|
|
105
|
-
// this.bot.command('publish', async (ctx) => {
|
|
106
|
-
// console.log(ctx.message)
|
|
107
|
-
// if (!ctx.message.reply_to_message) {
|
|
108
|
-
// return ctx.reply('Please reply to a message you want to tag.');
|
|
109
|
-
// }
|
|
110
|
-
// const tags = ctx.message.text.split(' ').slice(1);
|
|
111
|
-
// if (tags.length === 0) {
|
|
112
|
-
// return ctx.reply('Please provide at least one tag.');
|
|
113
|
-
// }
|
|
114
|
-
|
|
115
|
-
// const messageID = ctx.message.reply_to_message.message_id;
|
|
116
|
-
// const chatID = ctx.message.chat.id;
|
|
117
|
-
// const messageContent = ctx.message.reply_to_message.text;
|
|
118
|
-
// let settings = await this.db.get('settings', chatID)
|
|
119
|
-
// let hex = settings.hex
|
|
120
|
-
|
|
121
|
-
// for (let tag of tags) {
|
|
122
|
-
// let node = await this.gun.get(chatID + '/' + messageID).put({ id: chatID + '/' + messageID, content: messageContent })
|
|
123
|
-
// await this.put(hex, tag, node)
|
|
124
|
-
// }
|
|
125
|
-
|
|
126
|
-
// ctx.reply('Tag published.');
|
|
127
|
-
// });
|
|
128
|
-
|
|
129
31
|
}
|
|
130
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Sets the JSON schema for a specific lense.
|
|
35
|
+
* @param {string} lense - The lense identifier.
|
|
36
|
+
* @param {object} schema - The JSON schema to set.
|
|
37
|
+
* @returns {Promise} - Resolves when the schema is set.
|
|
38
|
+
*/
|
|
131
39
|
async setSchema(lense, schema) {
|
|
132
40
|
return new Promise((resolve, reject) => {
|
|
133
41
|
this.gun.get(lense).get('schema').put(JSON.stringify(schema), ack => {
|
|
@@ -141,6 +49,11 @@ class HoloSphere {
|
|
|
141
49
|
})
|
|
142
50
|
}
|
|
143
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Retrieves the JSON schema for a specific lense.
|
|
54
|
+
* @param {string} lense - The lense identifier.
|
|
55
|
+
* @returns {Promise<object|null>} - The retrieved schema or null if not found.
|
|
56
|
+
*/
|
|
144
57
|
async getSchema(lense) {
|
|
145
58
|
return new Promise((resolve) => {
|
|
146
59
|
this.gun.get(lense).get('schema').once(data => {
|
|
@@ -159,28 +72,21 @@ class HoloSphere {
|
|
|
159
72
|
})
|
|
160
73
|
})
|
|
161
74
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
this.db.gun.get('settings').get(chatID).put(hex)
|
|
168
|
-
return hex
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async getHexContent(ctx) {
|
|
172
|
-
const chatID = ctx.message.chat.id;
|
|
173
|
-
let settings = await this.getSettings(chatID)
|
|
174
|
-
let hex = settings.hex
|
|
175
|
-
let content = await this.db.getAll(hex + '/tags')
|
|
176
|
-
//console.log(content)
|
|
177
|
-
return content ? content[0].id : 'not found'
|
|
178
|
-
}
|
|
179
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Deletes a specific tag from a given ID.
|
|
77
|
+
* @param {string} id - The identifier from which to delete the tag.
|
|
78
|
+
* @param {string} tag - The tag to delete.
|
|
79
|
+
*/
|
|
180
80
|
async delete(id, tag) {
|
|
181
81
|
await this.gun.get(id).get(tag).put(null)
|
|
182
82
|
}
|
|
183
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Stores content in the specified hex and lense.
|
|
86
|
+
* @param {string} hex - The hex identifier.
|
|
87
|
+
* @param {string} lense - The lense under which to store the content.
|
|
88
|
+
* @param {object} content - The content to store.
|
|
89
|
+
*/
|
|
184
90
|
async put(hex, lense, content) {
|
|
185
91
|
// Retrieve the schema for the lense
|
|
186
92
|
let schema = await this.getSchema(lense)
|
|
@@ -202,28 +108,47 @@ class HoloSphere {
|
|
|
202
108
|
noderef = this.gun.get(lense).get(content.id).put(payload)
|
|
203
109
|
this.gun.get(hex.toString()).get(lense).get(content.id).put(payload)
|
|
204
110
|
} else { // create a content-addressable reference like IPFS. Note: no updates possible using put
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
noderef = this.gun.get(lense).get(hash).put(payload)
|
|
211
|
-
this.gun.get(hex.toString()).get(lense).get(hash).put(payload)
|
|
111
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(payload));
|
|
112
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
113
|
+
const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, "0")).join("");
|
|
114
|
+
noderef = this.gun.get(lense).get(hashHex).put(payload)
|
|
115
|
+
this.gun.get(hex.toString()).get(lense).get(hashHex).put(payload)
|
|
212
116
|
}
|
|
213
117
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// console.log('Content added successfully under tag:', lense);
|
|
220
|
-
// resolve(ack);
|
|
221
|
-
// }
|
|
222
|
-
// });
|
|
223
|
-
// });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async putNode(hex, lense, node) {
|
|
121
|
+
this.gun.get(hex).get(lense).set(node)
|
|
122
|
+
}
|
|
224
123
|
|
|
124
|
+
async parse(data) {
|
|
125
|
+
var parsed = {}
|
|
126
|
+
|
|
127
|
+
if (data._ && data._["#"]) {
|
|
128
|
+
// If the data is a reference, fetch the actual content
|
|
129
|
+
let query = data._['#'].split('/')
|
|
130
|
+
let hex = query[1]
|
|
131
|
+
let lense = query[2]
|
|
132
|
+
let key = query[3]
|
|
133
|
+
parsed = await this.getKey(hex, lense, key)
|
|
134
|
+
|
|
135
|
+
} else
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
parsed = JSON.parse(data);
|
|
139
|
+
} catch (e) {
|
|
140
|
+
console.log('Invalid JSON:', data);
|
|
141
|
+
parsed = data //return the raw data
|
|
142
|
+
}
|
|
143
|
+
return parsed
|
|
225
144
|
}
|
|
226
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Retrieves content from the specified hex and lense.
|
|
148
|
+
* @param {string} hex - The hex identifier.
|
|
149
|
+
* @param {string} lense - The lense from which to retrieve content.
|
|
150
|
+
* @returns {Promise<Array<object>>} - The retrieved content.
|
|
151
|
+
*/
|
|
227
152
|
async get(hex, lense) {
|
|
228
153
|
// Wrap the GunDB operation in a promise
|
|
229
154
|
//retrieve lense schema
|
|
@@ -244,18 +169,8 @@ class HoloSphere {
|
|
|
244
169
|
this.gun.get(hex.toString()).get(lense).map().once(async (itemdata, key) => {
|
|
245
170
|
counter += 1
|
|
246
171
|
if (itemdata) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
// itemdata = await this.gun.get(itemdata._['#']).then();
|
|
250
|
-
// console.log("Data :",itemdata)
|
|
251
|
-
// }
|
|
252
|
-
var parsed = {}
|
|
253
|
-
try {
|
|
254
|
-
parsed = JSON.parse(itemdata);
|
|
255
|
-
} catch (e) {
|
|
256
|
-
console.log('Invalid JSON:', itemdata);
|
|
257
|
-
parsed = itemdata //return the raw data
|
|
258
|
-
}
|
|
172
|
+
let parsed = await this.parse (itemdata)
|
|
173
|
+
|
|
259
174
|
|
|
260
175
|
if (schema) {
|
|
261
176
|
let valid = this.validator.validate(schema, parsed);
|
|
@@ -283,8 +198,47 @@ class HoloSphere {
|
|
|
283
198
|
);
|
|
284
199
|
}
|
|
285
200
|
|
|
286
|
-
|
|
201
|
+
/**
|
|
202
|
+
* Retrieves a specific key from the specified hex and lense.
|
|
203
|
+
* @param {string} hex - The hex identifier.
|
|
204
|
+
* @param {string} lense - The lense from which to retrieve the key.
|
|
205
|
+
* @param {string} key - The specific key to retrieve.
|
|
206
|
+
* @returns {Promise<object|null>} - The retrieved content or null if not found.
|
|
207
|
+
*/
|
|
208
|
+
async getKey(hex, lense, key) {
|
|
209
|
+
return new Promise((resolve) => {
|
|
210
|
+
// Use Gun to get the data
|
|
211
|
+
this.gun.get(hex).get(lense).get(key).once((data, key) => {
|
|
212
|
+
if (data) {
|
|
213
|
+
resolve(JSON.parse(data)); // Resolve the promise with the data if data is found
|
|
214
|
+
} else {
|
|
215
|
+
resolve(null); // Reject the promise if no data is found
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Retrieves a specific gundb node from the specified hex and lense.
|
|
224
|
+
* @param {string} hex - The hex identifier.
|
|
225
|
+
* @param {string} lense - The lense from which to retrieve the key.
|
|
226
|
+
* @param {string} key - The specific key to retrieve.
|
|
227
|
+
* @returns {Promise<object|null>} - The retrieved content or null if not found.
|
|
228
|
+
*/
|
|
229
|
+
getNode(hex, lense, key) {
|
|
230
|
+
// Use Gun to get the data
|
|
231
|
+
return this.gun.get(hex).get(lense).get(key)
|
|
232
|
+
}
|
|
233
|
+
|
|
287
234
|
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Computes summaries based on the content within a hex and lense.
|
|
238
|
+
* @param {string} hex - The hex identifier.
|
|
239
|
+
* @param {string} lense - The lense to compute.
|
|
240
|
+
* @param {string} operation - The operation to perform.
|
|
241
|
+
*/
|
|
288
242
|
async compute(hex, lense, operation) {
|
|
289
243
|
|
|
290
244
|
let res = h3.getResolution(hex);
|
|
@@ -304,7 +258,7 @@ class HoloSphere {
|
|
|
304
258
|
resolve(); // Resolve the promise to prevent it from hanging
|
|
305
259
|
}, 1000); // Timeout of 5 seconds
|
|
306
260
|
|
|
307
|
-
this.
|
|
261
|
+
this.gun.get(siblings[i]).get(lense).map().once((data, key) => {
|
|
308
262
|
clearTimeout(timeout); // Clear the timeout if data is received
|
|
309
263
|
if (data) {
|
|
310
264
|
content.push(data.content);
|
|
@@ -324,6 +278,11 @@ class HoloSphere {
|
|
|
324
278
|
this.compute(parent, lense, operation)
|
|
325
279
|
}
|
|
326
280
|
|
|
281
|
+
/**
|
|
282
|
+
* Clears all entities under a specific hex and lense.
|
|
283
|
+
* @param {string} hex - The hex identifier.
|
|
284
|
+
* @param {string} lense - The lense to clear.
|
|
285
|
+
*/
|
|
327
286
|
async clearlense(hex, lense) {
|
|
328
287
|
let entities = {};
|
|
329
288
|
|
|
@@ -336,6 +295,11 @@ class HoloSphere {
|
|
|
336
295
|
}
|
|
337
296
|
|
|
338
297
|
|
|
298
|
+
/**
|
|
299
|
+
* Summarizes provided history text using OpenAI.
|
|
300
|
+
* @param {string} history - The history text to summarize.
|
|
301
|
+
* @returns {Promise<string>} - The summarized text.
|
|
302
|
+
*/
|
|
339
303
|
async summarize(history) {
|
|
340
304
|
if (!this.openai) {
|
|
341
305
|
return 'OpenAI not initialized, please specify the API key in the constructor.'
|
|
@@ -368,21 +332,34 @@ class HoloSphere {
|
|
|
368
332
|
return summary
|
|
369
333
|
}
|
|
370
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Upcasts content to parent hexagons recursively.
|
|
337
|
+
* @param {string} hex - The current hex identifier.
|
|
338
|
+
* @param {string} lense - The lense under which to upcast.
|
|
339
|
+
* @param {object} content - The content to upcast.
|
|
340
|
+
* @returns {Promise<object>} - The upcasted content.
|
|
341
|
+
*/
|
|
371
342
|
async upcast(hex, lense, content) {
|
|
372
343
|
let res = h3.getResolution(hex)
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
console.log('Upcasting ', hex, lense, content)
|
|
376
|
-
let parent = h3.cellToParent(hex, res - 1)
|
|
377
|
-
await this.put(parent, lense, content)
|
|
378
|
-
if (res == 0)
|
|
344
|
+
if (res == 0) {
|
|
345
|
+
await this.putNode(hex, lense, content)
|
|
379
346
|
return content
|
|
380
|
-
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
console.log('Upcasting ', hex, lense, content, res)
|
|
350
|
+
await this.putNode(hex, lense, content)
|
|
351
|
+
let parent = h3.cellToParent(hex, res - 1)
|
|
381
352
|
return this.upcast(parent, lense, content)
|
|
353
|
+
}
|
|
382
354
|
}
|
|
383
355
|
|
|
384
356
|
|
|
385
|
-
|
|
357
|
+
/**
|
|
358
|
+
* Updates the parent hexagon with a new report.
|
|
359
|
+
* @param {string} id - The child hex identifier.
|
|
360
|
+
* @param {string} report - The report to update.
|
|
361
|
+
* @returns {Promise<object>} - The updated parent information.
|
|
362
|
+
*/
|
|
386
363
|
async updateParent(id, report) {
|
|
387
364
|
let cellinfo = await this.getCellInfo(id)
|
|
388
365
|
let res = h3.getResolution(id)
|
|
@@ -398,11 +375,23 @@ class HoloSphere {
|
|
|
398
375
|
}
|
|
399
376
|
|
|
400
377
|
|
|
378
|
+
/**
|
|
379
|
+
* Converts latitude and longitude to a hex identifier.
|
|
380
|
+
* @param {number} lat - The latitude.
|
|
381
|
+
* @param {number} lng - The longitude.
|
|
382
|
+
* @param {number} resolution - The resolution level.
|
|
383
|
+
* @returns {Promise<string>} - The resulting hex identifier.
|
|
384
|
+
*/
|
|
401
385
|
async getHex(lat, lng, resolution) {
|
|
402
386
|
return h3.latLngToCell(lat, lng, resolution);
|
|
403
387
|
}
|
|
404
388
|
|
|
405
|
-
|
|
389
|
+
/**
|
|
390
|
+
* Retrieves all containing hexagons at all scales for given coordinates.
|
|
391
|
+
* @param {number} lat - The latitude.
|
|
392
|
+
* @param {number} lng - The longitude.
|
|
393
|
+
* @returns {Array<string>} - List of hex identifiers.
|
|
394
|
+
*/
|
|
406
395
|
getScalespace(lat, lng) {
|
|
407
396
|
let list = []
|
|
408
397
|
let cell = h3.latLngToCell(lat, lng, 14);
|
|
@@ -413,7 +402,11 @@ class HoloSphere {
|
|
|
413
402
|
return list
|
|
414
403
|
}
|
|
415
404
|
|
|
416
|
-
|
|
405
|
+
/**
|
|
406
|
+
* Retrieves all containing hexagons at all scales for a given hex.
|
|
407
|
+
* @param {string} hex - The hex identifier.
|
|
408
|
+
* @returns {Array<string>} - List of hex identifiers.
|
|
409
|
+
*/
|
|
417
410
|
getHexScalespace(hex) {
|
|
418
411
|
let list = []
|
|
419
412
|
let res = h3.getResolution(hex)
|
|
@@ -423,43 +416,73 @@ class HoloSphere {
|
|
|
423
416
|
return list
|
|
424
417
|
}
|
|
425
418
|
|
|
419
|
+
/**
|
|
420
|
+
* Subscribes to changes in a specific hex and lense.
|
|
421
|
+
* @param {string} hex - The hex identifier.
|
|
422
|
+
* @param {string} lense - The lense to subscribe to.
|
|
423
|
+
* @param {function} callback - The callback to execute on changes.
|
|
424
|
+
*/
|
|
426
425
|
subscribe(hex, lense, callback) {
|
|
427
426
|
this.gun.get(hex).get(lense).map().on((data, key) => {
|
|
428
427
|
callback(data, key)
|
|
429
428
|
})
|
|
430
429
|
}
|
|
431
430
|
|
|
432
|
-
|
|
431
|
+
/**
|
|
432
|
+
* Retrieves the final vote for a user, considering delegations.
|
|
433
|
+
* @param {string} userId - The user's identifier.
|
|
434
|
+
* @param {string} topic - The voting topic.
|
|
435
|
+
* @param {object} votes - The current votes.
|
|
436
|
+
* @param {Set<string>} [visited=new Set()] - Set of visited users to prevent cycles.
|
|
437
|
+
* @returns {string|null} - The final vote or null if not found.
|
|
438
|
+
*/
|
|
439
|
+
getFinalVote(userId, topic, votes, visited = new Set()) {
|
|
440
|
+
if (this.users[userId]) { // Added this.users
|
|
441
|
+
if (visited.has(userId)) {
|
|
442
|
+
return null; // Avoid circular delegations
|
|
443
|
+
}
|
|
444
|
+
visited.add(userId);
|
|
433
445
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
visited.add(userId);
|
|
446
|
+
const delegation = this.users[userId].delegations[topic];
|
|
447
|
+
if (delegation && votes[delegation] === undefined) {
|
|
448
|
+
return this.getFinalVote(delegation, topic, votes, visited); // Prefixed with this
|
|
449
|
+
}
|
|
439
450
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
451
|
+
return votes[userId] !== undefined ? votes[userId] : null;
|
|
452
|
+
}
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
444
455
|
|
|
445
|
-
|
|
446
|
-
|
|
456
|
+
/**
|
|
457
|
+
* Aggregates votes for a specific hex and topic.
|
|
458
|
+
* @param {string} hexId - The hex identifier.
|
|
459
|
+
* @param {string} topic - The voting topic.
|
|
460
|
+
* @returns {object} - Aggregated vote counts.
|
|
461
|
+
*/
|
|
462
|
+
aggregateVotes(hexId, topic) {
|
|
463
|
+
if (!this.hexagonVotes[hexId] || !this.hexagonVotes[hexId][topic]) {
|
|
464
|
+
return {}; // Handle undefined votes
|
|
465
|
+
}
|
|
466
|
+
const votes = this.hexagonVotes[hexId][topic];
|
|
467
|
+
const aggregatedVotes = {};
|
|
447
468
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
469
|
+
Object.keys(votes).forEach(userId => {
|
|
470
|
+
const finalVote = this.getFinalVote(userId, topic, votes); // Prefixed with this
|
|
471
|
+
if (finalVote !== null) {
|
|
472
|
+
aggregatedVotes[finalVote] = (aggregatedVotes[finalVote] || 0) + 1;
|
|
473
|
+
}
|
|
474
|
+
});
|
|
451
475
|
|
|
452
|
-
|
|
453
|
-
const finalVote = getFinalVote(userId, topic, votes);
|
|
454
|
-
if (finalVote !== null) {
|
|
455
|
-
aggregatedVotes[finalVote] = (aggregatedVotes[finalVote] || 0) + 1;
|
|
476
|
+
return aggregatedVotes;
|
|
456
477
|
}
|
|
457
|
-
});
|
|
458
|
-
|
|
459
|
-
return aggregatedVotes;
|
|
460
|
-
}
|
|
461
478
|
|
|
462
|
-
|
|
479
|
+
/**
|
|
480
|
+
* Delegates a user's vote to another user.
|
|
481
|
+
* @param {string} userId - The user's identifier.
|
|
482
|
+
* @param {string} topic - The voting topic.
|
|
483
|
+
* @param {string} delegateTo - The user to delegate the vote to.
|
|
484
|
+
*/
|
|
485
|
+
async delegateVote(userId, topic, delegateTo) {
|
|
463
486
|
const response = await fetch('/delegate', {
|
|
464
487
|
method: 'POST',
|
|
465
488
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -468,6 +491,13 @@ async delegateVote(userId, topic, delegateTo) {
|
|
|
468
491
|
alert(await response.text());
|
|
469
492
|
}
|
|
470
493
|
|
|
494
|
+
/**
|
|
495
|
+
* Casts a vote for a user on a specific topic and hex.
|
|
496
|
+
* @param {string} userId - The user's identifier.
|
|
497
|
+
* @param {string} hexId - The hex identifier.
|
|
498
|
+
* @param {string} topic - The voting topic.
|
|
499
|
+
* @param {string} vote - The vote choice.
|
|
500
|
+
*/
|
|
471
501
|
async vote(userId, hexId, topic, vote) {
|
|
472
502
|
const response = await fetch('/vote', {
|
|
473
503
|
method: 'POST',
|
|
@@ -478,6 +508,8 @@ async delegateVote(userId, topic, delegateTo) {
|
|
|
478
508
|
}
|
|
479
509
|
|
|
480
510
|
|
|
511
|
+
|
|
512
|
+
|
|
481
513
|
}
|
|
482
514
|
|
|
483
515
|
export default HoloSphere;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "holosphere",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Holonic Geospatial Communication Infrastructure based on h3.js and gun.js",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "holosphere.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "echo \"Error: no test specified\" && exit 1"
|