holosphere 1.0.3 → 1.0.5

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/hexlib.js ADDED
@@ -0,0 +1,332 @@
1
+ // Generated code -- CC0 -- No Rights Reserved -- http://www.redblobgames.com/grids/hexagons/
2
+ export class Point {
3
+ constructor(x, y) {
4
+ this.x = x;
5
+ this.y = y;
6
+ }
7
+ }
8
+ export class Hex {
9
+ constructor(q, r, s) {
10
+ this.q = q;
11
+ this.r = r;
12
+ this.s = s;
13
+ if (Math.round(q + r + s) !== 0)
14
+ throw "q + r + s must be 0";
15
+ }
16
+ add(b) {
17
+ return new Hex(this.q + b.q, this.r + b.r, this.s + b.s);
18
+ }
19
+ subtract(b) {
20
+ return new Hex(this.q - b.q, this.r - b.r, this.s - b.s);
21
+ }
22
+ scale(k) {
23
+ return new Hex(this.q * k, this.r * k, this.s * k);
24
+ }
25
+ rotateLeft() {
26
+ return new Hex(-this.s, -this.q, -this.r);
27
+ }
28
+ rotateRight() {
29
+ return new Hex(-this.r, -this.s, -this.q);
30
+ }
31
+ static direction(direction) {
32
+ return Hex.directions[direction];
33
+ }
34
+ neighbor(direction) {
35
+ return this.add(Hex.direction(direction));
36
+ }
37
+ diagonalNeighbor(direction) {
38
+ return this.add(Hex.diagonals[direction]);
39
+ }
40
+ len() {
41
+ return (Math.abs(this.q) + Math.abs(this.r) + Math.abs(this.s)) / 2;
42
+ }
43
+ distance(b) {
44
+ return this.subtract(b).len();
45
+ }
46
+ round() {
47
+ var qi = Math.round(this.q);
48
+ var ri = Math.round(this.r);
49
+ var si = Math.round(this.s);
50
+ var q_diff = Math.abs(qi - this.q);
51
+ var r_diff = Math.abs(ri - this.r);
52
+ var s_diff = Math.abs(si - this.s);
53
+ if (q_diff > r_diff && q_diff > s_diff) {
54
+ qi = -ri - si;
55
+ }
56
+ else if (r_diff > s_diff) {
57
+ ri = -qi - si;
58
+ }
59
+ else {
60
+ si = -qi - ri;
61
+ }
62
+ return new Hex(qi, ri, si);
63
+ }
64
+ lerp(b, t) {
65
+ return new Hex(this.q * (1.0 - t) + b.q * t, this.r * (1.0 - t) + b.r * t, this.s * (1.0 - t) + b.s * t);
66
+ }
67
+ linedraw(b) {
68
+ var N = this.distance(b);
69
+ var a_nudge = new Hex(this.q + 1e-06, this.r + 1e-06, this.s - 2e-06);
70
+ var b_nudge = new Hex(b.q + 1e-06, b.r + 1e-06, b.s - 2e-06);
71
+ var results = [];
72
+ var step = 1.0 / Math.max(N, 1);
73
+ for (var i = 0; i <= N; i++) {
74
+ results.push(a_nudge.lerp(b_nudge, step * i).round());
75
+ }
76
+ return results;
77
+ }
78
+ }
79
+ Hex.directions = [new Hex(1, 0, -1), new Hex(1, -1, 0), new Hex(0, -1, 1), new Hex(-1, 0, 1), new Hex(-1, 1, 0), new Hex(0, 1, -1)];
80
+ Hex.diagonals = [new Hex(2, -1, -1), new Hex(1, -2, 1), new Hex(-1, -1, 2), new Hex(-2, 1, 1), new Hex(-1, 2, -1), new Hex(1, 1, -2)];
81
+ export class OffsetCoord {
82
+ constructor(col, row) {
83
+ this.col = col;
84
+ this.row = row;
85
+ }
86
+ static qoffsetFromCube(offset, h) {
87
+ var col = h.q;
88
+ var row = h.r + (h.q + offset * (h.q & 1)) / 2;
89
+ if (offset !== OffsetCoord.EVEN && offset !== OffsetCoord.ODD) {
90
+ throw "offset must be EVEN (+1) or ODD (-1)";
91
+ }
92
+ return new OffsetCoord(col, row);
93
+ }
94
+ static qoffsetToCube(offset, h) {
95
+ var q = h.col;
96
+ var r = h.row - (h.col + offset * (h.col & 1)) / 2;
97
+ var s = -q - r;
98
+ if (offset !== OffsetCoord.EVEN && offset !== OffsetCoord.ODD) {
99
+ throw "offset must be EVEN (+1) or ODD (-1)";
100
+ }
101
+ return new Hex(q, r, s);
102
+ }
103
+ static roffsetFromCube(offset, h) {
104
+ var col = h.q + (h.r + offset * (h.r & 1)) / 2;
105
+ var row = h.r;
106
+ if (offset !== OffsetCoord.EVEN && offset !== OffsetCoord.ODD) {
107
+ throw "offset must be EVEN (+1) or ODD (-1)";
108
+ }
109
+ return new OffsetCoord(col, row);
110
+ }
111
+ static roffsetToCube(offset, h) {
112
+ var q = h.col - (h.row + offset * (h.row & 1)) / 2;
113
+ var r = h.row;
114
+ var s = -q - r;
115
+ if (offset !== OffsetCoord.EVEN && offset !== OffsetCoord.ODD) {
116
+ throw "offset must be EVEN (+1) or ODD (-1)";
117
+ }
118
+ return new Hex(q, r, s);
119
+ }
120
+ }
121
+ OffsetCoord.EVEN = 1;
122
+ OffsetCoord.ODD = -1;
123
+ export class DoubledCoord {
124
+ constructor(col, row) {
125
+ this.col = col;
126
+ this.row = row;
127
+ }
128
+ static qdoubledFromCube(h) {
129
+ var col = h.q;
130
+ var row = 2 * h.r + h.q;
131
+ return new DoubledCoord(col, row);
132
+ }
133
+ qdoubledToCube() {
134
+ var q = this.col;
135
+ var r = (this.row - this.col) / 2;
136
+ var s = -q - r;
137
+ return new Hex(q, r, s);
138
+ }
139
+ static rdoubledFromCube(h) {
140
+ var col = 2 * h.q + h.r;
141
+ var row = h.r;
142
+ return new DoubledCoord(col, row);
143
+ }
144
+ rdoubledToCube() {
145
+ var q = (this.col - this.row) / 2;
146
+ var r = this.row;
147
+ var s = -q - r;
148
+ return new Hex(q, r, s);
149
+ }
150
+ }
151
+ export class Orientation {
152
+ constructor(f0, f1, f2, f3, b0, b1, b2, b3, start_angle) {
153
+ this.f0 = f0;
154
+ this.f1 = f1;
155
+ this.f2 = f2;
156
+ this.f3 = f3;
157
+ this.b0 = b0;
158
+ this.b1 = b1;
159
+ this.b2 = b2;
160
+ this.b3 = b3;
161
+ this.start_angle = start_angle;
162
+ }
163
+ }
164
+ export class Layout {
165
+ constructor(orientation, size, origin) {
166
+ this.orientation = orientation;
167
+ this.size = size;
168
+ this.origin = origin;
169
+ }
170
+ hexToPixel(h) {
171
+ var M = this.orientation;
172
+ var size = this.size;
173
+ var origin = this.origin;
174
+ var x = (M.f0 * h.q + M.f1 * h.r) * size.x;
175
+ var y = (M.f2 * h.q + M.f3 * h.r) * size.y;
176
+ return new Point(x + origin.x, y + origin.y);
177
+ }
178
+ pixelToHex(p) {
179
+ var M = this.orientation;
180
+ var size = this.size;
181
+ var origin = this.origin;
182
+ var pt = new Point((p.x - origin.x) / size.x, (p.y - origin.y) / size.y);
183
+ var q = M.b0 * pt.x + M.b1 * pt.y;
184
+ var r = M.b2 * pt.x + M.b3 * pt.y;
185
+ return new Hex(q, r, -q - r);
186
+ }
187
+ hexCornerOffset(corner) {
188
+ var M = this.orientation;
189
+ var size = this.size;
190
+ var angle = 2.0 * Math.PI * (M.start_angle - corner) / 6.0;
191
+ return new Point(size.x * Math.cos(angle), size.y * Math.sin(angle));
192
+ }
193
+ polygonCorners(h) {
194
+ var corners = [];
195
+ var center = this.hexToPixel(h);
196
+ for (var i = 0; i < 6; i++) {
197
+ var offset = this.hexCornerOffset(i);
198
+ corners.push(new Point(center.x + offset.x, center.y + offset.y));
199
+ }
200
+ return corners;
201
+ }
202
+ }
203
+ Layout.pointy = new Orientation(Math.sqrt(3.0), Math.sqrt(3.0) / 2.0, 0.0, 3.0 / 2.0, Math.sqrt(3.0) / 3.0, -1.0 / 3.0, 0.0, 2.0 / 3.0, 0.5);
204
+ Layout.flat = new Orientation(3.0 / 2.0, 0.0, Math.sqrt(3.0) / 2.0, Math.sqrt(3.0), 2.0 / 3.0, 0.0, -1.0 / 3.0, Math.sqrt(3.0) / 3.0, 0.0);
205
+ class Tests {
206
+ constructor() { }
207
+ static equalHex(name, a, b) {
208
+ if (!(a.q === b.q && a.s === b.s && a.r === b.r)) {
209
+ complain(name);
210
+ }
211
+ }
212
+ static equalOffsetcoord(name, a, b) {
213
+ if (!(a.col === b.col && a.row === b.row)) {
214
+ complain(name);
215
+ }
216
+ }
217
+ static equalDoubledcoord(name, a, b) {
218
+ if (!(a.col === b.col && a.row === b.row)) {
219
+ complain(name);
220
+ }
221
+ }
222
+ static equalInt(name, a, b) {
223
+ if (!(a === b)) {
224
+ complain(name);
225
+ }
226
+ }
227
+ static equalHexArray(name, a, b) {
228
+ Tests.equalInt(name, a.length, b.length);
229
+ for (var i = 0; i < a.length; i++) {
230
+ Tests.equalHex(name, a[i], b[i]);
231
+ }
232
+ }
233
+ static testHexArithmetic() {
234
+ Tests.equalHex("hex_add", new Hex(4, -10, 6), new Hex(1, -3, 2).add(new Hex(3, -7, 4)));
235
+ Tests.equalHex("hex_subtract", new Hex(-2, 4, -2), new Hex(1, -3, 2).subtract(new Hex(3, -7, 4)));
236
+ }
237
+ static testHexDirection() {
238
+ Tests.equalHex("hex_direction", new Hex(0, -1, 1), Hex.direction(2));
239
+ }
240
+ static testHexNeighbor() {
241
+ Tests.equalHex("hex_neighbor", new Hex(1, -3, 2), new Hex(1, -2, 1).neighbor(2));
242
+ }
243
+ static testHexDiagonal() {
244
+ Tests.equalHex("hex_diagonal", new Hex(-1, -1, 2), new Hex(1, -2, 1).diagonalNeighbor(3));
245
+ }
246
+ static testHexDistance() {
247
+ Tests.equalInt("hex_distance", 7, new Hex(3, -7, 4).distance(new Hex(0, 0, 0)));
248
+ }
249
+ static testHexRotateRight() {
250
+ Tests.equalHex("hex_rotate_right", new Hex(1, -3, 2).rotateRight(), new Hex(3, -2, -1));
251
+ }
252
+ static testHexRotateLeft() {
253
+ Tests.equalHex("hex_rotate_left", new Hex(1, -3, 2).rotateLeft(), new Hex(-2, -1, 3));
254
+ }
255
+ static testHexRound() {
256
+ var a = new Hex(0.0, 0.0, 0.0);
257
+ var b = new Hex(1.0, -1.0, 0.0);
258
+ var c = new Hex(0.0, -1.0, 1.0);
259
+ Tests.equalHex("hex_round 1", new Hex(5, -10, 5), new Hex(0.0, 0.0, 0.0).lerp(new Hex(10.0, -20.0, 10.0), 0.5).round());
260
+ Tests.equalHex("hex_round 2", a.round(), a.lerp(b, 0.499).round());
261
+ Tests.equalHex("hex_round 3", b.round(), a.lerp(b, 0.501).round());
262
+ Tests.equalHex("hex_round 4", a.round(), new Hex(a.q * 0.4 + b.q * 0.3 + c.q * 0.3, a.r * 0.4 + b.r * 0.3 + c.r * 0.3, a.s * 0.4 + b.s * 0.3 + c.s * 0.3).round());
263
+ Tests.equalHex("hex_round 5", c.round(), new Hex(a.q * 0.3 + b.q * 0.3 + c.q * 0.4, a.r * 0.3 + b.r * 0.3 + c.r * 0.4, a.s * 0.3 + b.s * 0.3 + c.s * 0.4).round());
264
+ }
265
+ static testHexLinedraw() {
266
+ Tests.equalHexArray("hex_linedraw", [new Hex(0, 0, 0), new Hex(0, -1, 1), new Hex(0, -2, 2), new Hex(1, -3, 2), new Hex(1, -4, 3), new Hex(1, -5, 4)], new Hex(0, 0, 0).linedraw(new Hex(1, -5, 4)));
267
+ }
268
+ static testLayout() {
269
+ var h = new Hex(3, 4, -7);
270
+ var flat = new Layout(Layout.flat, new Point(10.0, 15.0), new Point(35.0, 71.0));
271
+ Tests.equalHex("layout", h, flat.pixelToHex(flat.hexToPixel(h)).round());
272
+ var pointy = new Layout(Layout.pointy, new Point(10.0, 15.0), new Point(35.0, 71.0));
273
+ Tests.equalHex("layout", h, pointy.pixelToHex(pointy.hexToPixel(h)).round());
274
+ }
275
+ static testOffsetRoundtrip() {
276
+ var a = new Hex(3, 4, -7);
277
+ var b = new OffsetCoord(1, -3);
278
+ Tests.equalHex("conversion_roundtrip even-q", a, OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, a)));
279
+ Tests.equalOffsetcoord("conversion_roundtrip even-q", b, OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, b)));
280
+ Tests.equalHex("conversion_roundtrip odd-q", a, OffsetCoord.qoffsetToCube(OffsetCoord.ODD, OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, a)));
281
+ Tests.equalOffsetcoord("conversion_roundtrip odd-q", b, OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, OffsetCoord.qoffsetToCube(OffsetCoord.ODD, b)));
282
+ Tests.equalHex("conversion_roundtrip even-r", a, OffsetCoord.roffsetToCube(OffsetCoord.EVEN, OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, a)));
283
+ Tests.equalOffsetcoord("conversion_roundtrip even-r", b, OffsetCoord.roffsetFromCube(OffsetCoord.EVEN, OffsetCoord.roffsetToCube(OffsetCoord.EVEN, b)));
284
+ Tests.equalHex("conversion_roundtrip odd-r", a, OffsetCoord.roffsetToCube(OffsetCoord.ODD, OffsetCoord.roffsetFromCube(OffsetCoord.ODD, a)));
285
+ Tests.equalOffsetcoord("conversion_roundtrip odd-r", b, OffsetCoord.roffsetFromCube(OffsetCoord.ODD, OffsetCoord.roffsetToCube(OffsetCoord.ODD, b)));
286
+ }
287
+ static testOffsetFromCube() {
288
+ Tests.equalOffsetcoord("offset_from_cube even-q", new OffsetCoord(1, 3), OffsetCoord.qoffsetFromCube(OffsetCoord.EVEN, new Hex(1, 2, -3)));
289
+ Tests.equalOffsetcoord("offset_from_cube odd-q", new OffsetCoord(1, 2), OffsetCoord.qoffsetFromCube(OffsetCoord.ODD, new Hex(1, 2, -3)));
290
+ }
291
+ static testOffsetToCube() {
292
+ Tests.equalHex("offset_to_cube even-", new Hex(1, 2, -3), OffsetCoord.qoffsetToCube(OffsetCoord.EVEN, new OffsetCoord(1, 3)));
293
+ Tests.equalHex("offset_to_cube odd-q", new Hex(1, 2, -3), OffsetCoord.qoffsetToCube(OffsetCoord.ODD, new OffsetCoord(1, 2)));
294
+ }
295
+ static testDoubledRoundtrip() {
296
+ var a = new Hex(3, 4, -7);
297
+ var b = new DoubledCoord(1, -3);
298
+ Tests.equalHex("conversion_roundtrip doubled-q", a, DoubledCoord.qdoubledFromCube(a).qdoubledToCube());
299
+ Tests.equalDoubledcoord("conversion_roundtrip doubled-q", b, DoubledCoord.qdoubledFromCube(b.qdoubledToCube()));
300
+ Tests.equalHex("conversion_roundtrip doubled-r", a, DoubledCoord.rdoubledFromCube(a).rdoubledToCube());
301
+ Tests.equalDoubledcoord("conversion_roundtrip doubled-r", b, DoubledCoord.rdoubledFromCube(b.rdoubledToCube()));
302
+ }
303
+ static testDoubledFromCube() {
304
+ Tests.equalDoubledcoord("doubled_from_cube doubled-q", new DoubledCoord(1, 5), DoubledCoord.qdoubledFromCube(new Hex(1, 2, -3)));
305
+ Tests.equalDoubledcoord("doubled_from_cube doubled-r", new DoubledCoord(4, 2), DoubledCoord.rdoubledFromCube(new Hex(1, 2, -3)));
306
+ }
307
+ static testDoubledToCube() {
308
+ Tests.equalHex("doubled_to_cube doubled-q", new Hex(1, 2, -3), new DoubledCoord(1, 5).qdoubledToCube());
309
+ Tests.equalHex("doubled_to_cube doubled-r", new Hex(1, 2, -3), new DoubledCoord(4, 2).rdoubledToCube());
310
+ }
311
+ static testAll() {
312
+ Tests.testHexArithmetic();
313
+ Tests.testHexDirection();
314
+ Tests.testHexNeighbor();
315
+ Tests.testHexDiagonal();
316
+ Tests.testHexDistance();
317
+ Tests.testHexRotateRight();
318
+ Tests.testHexRotateLeft();
319
+ Tests.testHexRound();
320
+ Tests.testHexLinedraw();
321
+ Tests.testLayout();
322
+ Tests.testOffsetRoundtrip();
323
+ Tests.testOffsetFromCube();
324
+ Tests.testOffsetToCube();
325
+ Tests.testDoubledRoundtrip();
326
+ Tests.testDoubledFromCube();
327
+ Tests.testDoubledToCube();
328
+ }
329
+ }
330
+ // Tests
331
+ function complain(name) { console.log("FAIL", name); }
332
+ Tests.testAll();
@@ -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
+ }
@@ -2,13 +2,17 @@ import * as h3 from 'h3-js';
2
2
  import OpenAI from 'openai';
3
3
  import Gun from 'gun'
4
4
  import Ajv2019 from 'ajv/dist/2019.js'
5
- import { createHash } from "crypto";
6
5
 
7
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
+ */
8
12
  constructor(appname, openaikey = null) {
9
13
  this.validator = new Ajv2019({ allErrors: false, strict: false });
10
14
  this.gun = Gun({
11
- peers: [ 'http://localhost:8765','http://gun.holons.io', 'https://gun-eu.herokuapp.com/gun','https://59.src.eco/gun'],
15
+ peers: ['https://59.src.eco/gun'],
12
16
  axe: false,
13
17
  // uuid: (content) => { // generate a unique id for each node
14
18
  // console.log('uuid', content);
@@ -16,119 +20,22 @@ class HoloSphere {
16
20
  });
17
21
 
18
22
  this.gun = this.gun.get(appname)
23
+ this.users = {}; // Initialize users
24
+ this.hexagonVotes = {}; // Initialize hexagonVotes
19
25
 
20
26
  if (openaikey != null) {
21
27
  this.openai = new OpenAI({
22
28
  apiKey: openaikey,
23
29
  });
24
30
  }
25
-
26
- //this.bot.command('sethex', async (ctx) => { this.setHex(ctx) }) TODO: MOVE HERE FROM SETTINGS
27
-
28
- // this.bot.command('resethex', async (ctx) => {
29
- // let chatID = ctx.message.chat.id;
30
- // let hex = (await this.db.get('settings', chatID)).hex
31
- // this.delete(hex, ctx.message.text.split(' ')[1])
32
- // })
33
-
34
- // this.bot.command('get', async (ctx) => {
35
- // const chatID = ctx.message.chat.id;
36
- // const lense = ctx.message.text.split(' ')[1];
37
- // if (!lense) {
38
- // return ctx.reply('Please specify a tag.');
39
- // }
40
- // let hex = (await this.db.get('settings', chatID)).hex
41
- // //let hex = settings.hex
42
- // console.log('hex', hex)
43
-
44
- // let data = await this.get(ctx, hex, lense)
45
-
46
- // })
47
-
48
- // this.bot.command('gethex', async (ctx) => {
49
- // let settings = await this.db.get('settings', chatID)
50
- // let id = settings.hex ? settings.hex : 'Hex not set, use /sethex'
51
- // ctx.reply(id)
52
- // })
53
-
54
- // this.bot.command('compute', async (ctx) => {
55
- // const chatID = ctx.message.chat.id;
56
- // let operation = ctx.message.text.split(' ')[1];
57
- // if (operation != 'sum') {
58
- // ctx.reply('Operation not implemented')
59
- // return
60
- // }
61
- // let lense = ctx.message.text.split(' ')[2]
62
- // if (!lense) {
63
- // ctx.reply('Please specify a lense where to perform the operation ')
64
- // return
65
- // }
66
- // let hex = (await this.db.get('settings', chatID)).hex
67
- // await this.compute(hex, lense, operation)
68
-
69
- // // let parentInfo = await this.getCellInfo(parent)
70
- // // parentInfo.wisdom[id] = report
71
- // // //update summary
72
- // // let summary = await this.summarize(Object.values(parentInfo.wisdom).join('\n'))
73
- // // parentInfo.summary = summary
74
-
75
- // // await this.db.put('cell', parentInfo)
76
- // // return parentInfo
77
-
78
- // // let content = await this.db.getAll(hex+'/tags')
79
- // })
80
-
81
-
82
-
83
-
84
- // this.bot.command('cast', async (ctx) => {
85
- // if (!ctx.message.reply_to_message) {
86
- // return ctx.reply('Please reply to a message you want to tag.');
87
- // }
88
- // const tags = ctx.message.text.split(' ').slice(1);
89
- // if (tags.length === 0) {
90
- // return ctx.reply('Please provide at least one tag.');
91
- // }
92
-
93
- // const messageID = ctx.message.reply_to_message.message_id;
94
- // const chatID = ctx.message.chat.id;
95
- // const messageContent = ctx.message.reply_to_message.text;
96
- // let settings = await this.db.get('settings', chatID)
97
- // let id = settings.hex ? settings.hex : 'Hex not set, use /sethex'
98
- // //create root node for the item
99
- // let node = await this.gun.get(chatID + '/' + messageID).put({ id: chatID + '/' + messageID, content: messageContent })
100
- // for (let tag of tags) {
101
- // await this.gun.get(id).get(tag).set(node)
102
- // this.upcast(id, tag, node)
103
- // }
104
- // })
105
-
106
- // this.bot.command('publish', async (ctx) => {
107
- // console.log(ctx.message)
108
- // if (!ctx.message.reply_to_message) {
109
- // return ctx.reply('Please reply to a message you want to tag.');
110
- // }
111
- // const tags = ctx.message.text.split(' ').slice(1);
112
- // if (tags.length === 0) {
113
- // return ctx.reply('Please provide at least one tag.');
114
- // }
115
-
116
- // const messageID = ctx.message.reply_to_message.message_id;
117
- // const chatID = ctx.message.chat.id;
118
- // const messageContent = ctx.message.reply_to_message.text;
119
- // let settings = await this.db.get('settings', chatID)
120
- // let hex = settings.hex
121
-
122
- // for (let tag of tags) {
123
- // let node = await this.gun.get(chatID + '/' + messageID).put({ id: chatID + '/' + messageID, content: messageContent })
124
- // await this.put(hex, tag, node)
125
- // }
126
-
127
- // ctx.reply('Tag published.');
128
- // });
129
-
130
31
  }
131
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
+ */
132
39
  async setSchema(lense, schema) {
133
40
  return new Promise((resolve, reject) => {
134
41
  this.gun.get(lense).get('schema').put(JSON.stringify(schema), ack => {
@@ -142,6 +49,11 @@ class HoloSphere {
142
49
  })
143
50
  }
144
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
+ */
145
57
  async getSchema(lense) {
146
58
  return new Promise((resolve) => {
147
59
  this.gun.get(lense).get('schema').once(data => {
@@ -160,28 +72,21 @@ class HoloSphere {
160
72
  })
161
73
  })
162
74
  }
163
-
164
- async setHex(ctx) {
165
- const chatID = ctx.message.chat.id;
166
- const hex = ctx.message.text.split(' ')[1];
167
- this.db.gun.get(hex).set('chats').put(chatID)
168
- this.db.gun.get('settings').get(chatID).put(hex)
169
- return hex
170
- }
171
-
172
- async getHexContent(ctx) {
173
- const chatID = ctx.message.chat.id;
174
- let settings = await this.getSettings(chatID)
175
- let hex = settings.hex
176
- let content = await this.db.getAll(hex + '/tags')
177
- //console.log(content)
178
- return content ? content[0].id : 'not found'
179
- }
180
-
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
+ */
181
80
  async delete(id, tag) {
182
81
  await this.gun.get(id).get(tag).put(null)
183
82
  }
184
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
+ */
185
90
  async put(hex, lense, content) {
186
91
  // Retrieve the schema for the lense
187
92
  let schema = await this.getSchema(lense)
@@ -203,24 +108,25 @@ class HoloSphere {
203
108
  noderef = this.gun.get(lense).get(content.id).put(payload)
204
109
  this.gun.get(hex.toString()).get(lense).get(content.id).put(payload)
205
110
  } else { // create a content-addressable reference like IPFS. Note: no updates possible using put
206
- const hash = createHash("sha256").update(payload).digest("hex");
207
- noderef = this.gun.get(lense).get(hash).put(payload)
208
- 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)
209
116
  }
210
117
 
211
- // return new Promise((resolve, reject) => {
212
- // this.gun.get(hex.toString()).get(lense).set(noderef, ack => {
213
- // if (ack.err) {
214
- // reject(new Error('Failed to add content: ' + ack.err));
215
- // } else {
216
- // console.log('Content added successfully under tag:', lense);
217
- // resolve(ack);
218
- // }
219
- // });
220
- // });
118
+ }
221
119
 
120
+ async putNode(hex, lense, node) {
121
+ this.gun.get(hex).get(lense).set(node)
222
122
  }
223
123
 
124
+ /**
125
+ * Retrieves content from the specified hex and lense.
126
+ * @param {string} hex - The hex identifier.
127
+ * @param {string} lense - The lense from which to retrieve content.
128
+ * @returns {Promise<Array<object>>} - The retrieved content.
129
+ */
224
130
  async get(hex, lense) {
225
131
  // Wrap the GunDB operation in a promise
226
132
  //retrieve lense schema
@@ -241,11 +147,16 @@ class HoloSphere {
241
147
  this.gun.get(hex.toString()).get(lense).map().once(async (itemdata, key) => {
242
148
  counter += 1
243
149
  if (itemdata) {
244
- // if (itemdata._["#"]) {
245
- // // If the data is a reference, fetch the actual content
246
- // itemdata = await this.gun.get(itemdata._['#']).then();
247
- // console.log("Data :",itemdata)
248
- // }
150
+ if (itemdata._["#"]) {
151
+
152
+ // If the data is a reference, fetch the actual content
153
+ let query = itemdata._['#'].split('/')
154
+ let hex = query[1]
155
+ let lense = query[2]
156
+ let key = query[3]
157
+ itemdata = await this.getNode(hex, lense, key)
158
+
159
+ }
249
160
  var parsed = {}
250
161
  try {
251
162
  parsed = JSON.parse(itemdata);
@@ -280,8 +191,47 @@ class HoloSphere {
280
191
  );
281
192
  }
282
193
 
283
- // Operations
194
+ /**
195
+ * Retrieves a specific key from the specified hex and lense.
196
+ * @param {string} hex - The hex identifier.
197
+ * @param {string} lense - The lense from which to retrieve the key.
198
+ * @param {string} key - The specific key to retrieve.
199
+ * @returns {Promise<object|null>} - The retrieved content or null if not found.
200
+ */
201
+ async getKey(hex, lense, key) {
202
+ return new Promise((resolve) => {
203
+ // Use Gun to get the data
204
+ this.gun.get(hex).get(lense).get(key).once((data, key) => {
205
+ if (data) {
206
+ resolve(JSON.parse(data)); // Resolve the promise with the data if data is found
207
+ } else {
208
+ resolve(null); // Reject the promise if no data is found
209
+ }
210
+ });
211
+ });
212
+
213
+ }
214
+
215
+ /**
216
+ * Retrieves a specific gundb node from the specified hex and lense.
217
+ * @param {string} hex - The hex identifier.
218
+ * @param {string} lense - The lense from which to retrieve the key.
219
+ * @param {string} key - The specific key to retrieve.
220
+ * @returns {Promise<object|null>} - The retrieved content or null if not found.
221
+ */
222
+ getNode(hex, lense, key) {
223
+ // Use Gun to get the data
224
+ return this.gun.get(hex).get(lense).get(key)
225
+ }
226
+
227
+
284
228
 
229
+ /**
230
+ * Computes summaries based on the content within a hex and lense.
231
+ * @param {string} hex - The hex identifier.
232
+ * @param {string} lense - The lense to compute.
233
+ * @param {string} operation - The operation to perform.
234
+ */
285
235
  async compute(hex, lense, operation) {
286
236
 
287
237
  let res = h3.getResolution(hex);
@@ -301,7 +251,7 @@ class HoloSphere {
301
251
  resolve(); // Resolve the promise to prevent it from hanging
302
252
  }, 1000); // Timeout of 5 seconds
303
253
 
304
- this.db.gun.get(siblings[i]).get(lense).map().once((data, key) => {
254
+ this.gun.get(siblings[i]).get(lense).map().once((data, key) => {
305
255
  clearTimeout(timeout); // Clear the timeout if data is received
306
256
  if (data) {
307
257
  content.push(data.content);
@@ -321,6 +271,11 @@ class HoloSphere {
321
271
  this.compute(parent, lense, operation)
322
272
  }
323
273
 
274
+ /**
275
+ * Clears all entities under a specific hex and lense.
276
+ * @param {string} hex - The hex identifier.
277
+ * @param {string} lense - The lense to clear.
278
+ */
324
279
  async clearlense(hex, lense) {
325
280
  let entities = {};
326
281
 
@@ -333,6 +288,11 @@ class HoloSphere {
333
288
  }
334
289
 
335
290
 
291
+ /**
292
+ * Summarizes provided history text using OpenAI.
293
+ * @param {string} history - The history text to summarize.
294
+ * @returns {Promise<string>} - The summarized text.
295
+ */
336
296
  async summarize(history) {
337
297
  if (!this.openai) {
338
298
  return 'OpenAI not initialized, please specify the API key in the constructor.'
@@ -365,21 +325,34 @@ class HoloSphere {
365
325
  return summary
366
326
  }
367
327
 
328
+ /**
329
+ * Upcasts content to parent hexagons recursively.
330
+ * @param {string} hex - The current hex identifier.
331
+ * @param {string} lense - The lense under which to upcast.
332
+ * @param {object} content - The content to upcast.
333
+ * @returns {Promise<object>} - The upcasted content.
334
+ */
368
335
  async upcast(hex, lense, content) {
369
336
  let res = h3.getResolution(hex)
370
-
371
-
372
- console.log('Upcasting ', hex, lense, content)
373
- let parent = h3.cellToParent(hex, res - 1)
374
- await this.put(parent, lense, content)
375
- if (res == 0)
337
+ if (res == 0) {
338
+ await this.putNode(hex, lense, content)
376
339
  return content
377
- else
340
+ }
341
+ else {
342
+ console.log('Upcasting ', hex, lense, content, res)
343
+ await this.putNode(hex, lense, content)
344
+ let parent = h3.cellToParent(hex, res - 1)
378
345
  return this.upcast(parent, lense, content)
346
+ }
379
347
  }
380
348
 
381
349
 
382
- // send information upwards, triggers the parent to update its summary
350
+ /**
351
+ * Updates the parent hexagon with a new report.
352
+ * @param {string} id - The child hex identifier.
353
+ * @param {string} report - The report to update.
354
+ * @returns {Promise<object>} - The updated parent information.
355
+ */
383
356
  async updateParent(id, report) {
384
357
  let cellinfo = await this.getCellInfo(id)
385
358
  let res = h3.getResolution(id)
@@ -395,11 +368,23 @@ class HoloSphere {
395
368
  }
396
369
 
397
370
 
371
+ /**
372
+ * Converts latitude and longitude to a hex identifier.
373
+ * @param {number} lat - The latitude.
374
+ * @param {number} lng - The longitude.
375
+ * @param {number} resolution - The resolution level.
376
+ * @returns {Promise<string>} - The resulting hex identifier.
377
+ */
398
378
  async getHex(lat, lng, resolution) {
399
379
  return h3.latLngToCell(lat, lng, resolution);
400
380
  }
401
381
 
402
- // returns the list of all the containing hexagons at xall scales
382
+ /**
383
+ * Retrieves all containing hexagons at all scales for given coordinates.
384
+ * @param {number} lat - The latitude.
385
+ * @param {number} lng - The longitude.
386
+ * @returns {Array<string>} - List of hex identifiers.
387
+ */
403
388
  getScalespace(lat, lng) {
404
389
  let list = []
405
390
  let cell = h3.latLngToCell(lat, lng, 14);
@@ -410,7 +395,11 @@ class HoloSphere {
410
395
  return list
411
396
  }
412
397
 
413
- // returns the list of all the containing hexagons at xall scales
398
+ /**
399
+ * Retrieves all containing hexagons at all scales for a given hex.
400
+ * @param {string} hex - The hex identifier.
401
+ * @returns {Array<string>} - List of hex identifiers.
402
+ */
414
403
  getHexScalespace(hex) {
415
404
  let list = []
416
405
  let res = h3.getResolution(hex)
@@ -420,43 +409,73 @@ class HoloSphere {
420
409
  return list
421
410
  }
422
411
 
412
+ /**
413
+ * Subscribes to changes in a specific hex and lense.
414
+ * @param {string} hex - The hex identifier.
415
+ * @param {string} lense - The lense to subscribe to.
416
+ * @param {function} callback - The callback to execute on changes.
417
+ */
423
418
  subscribe(hex, lense, callback) {
424
419
  this.gun.get(hex).get(lense).map().on((data, key) => {
425
420
  callback(data, key)
426
421
  })
427
422
  }
428
423
 
429
- // VOTING SYSTEM
424
+ /**
425
+ * Retrieves the final vote for a user, considering delegations.
426
+ * @param {string} userId - The user's identifier.
427
+ * @param {string} topic - The voting topic.
428
+ * @param {object} votes - The current votes.
429
+ * @param {Set<string>} [visited=new Set()] - Set of visited users to prevent cycles.
430
+ * @returns {string|null} - The final vote or null if not found.
431
+ */
432
+ getFinalVote(userId, topic, votes, visited = new Set()) {
433
+ if (this.users[userId]) { // Added this.users
434
+ if (visited.has(userId)) {
435
+ return null; // Avoid circular delegations
436
+ }
437
+ visited.add(userId);
430
438
 
431
- getFinalVote(userId, topic, votes, visited = new Set()) {
432
- if (visited.has(userId)) {
433
- return null; // Avoid circular delegations
434
- }
435
- visited.add(userId);
439
+ const delegation = this.users[userId].delegations[topic];
440
+ if (delegation && votes[delegation] === undefined) {
441
+ return this.getFinalVote(delegation, topic, votes, visited); // Prefixed with this
442
+ }
436
443
 
437
- const delegation = users[userId].delegations[topic];
438
- if (delegation && votes[delegation] === undefined) {
439
- return getFinalVote(delegation, topic, votes, visited); // Follow delegation
440
- }
444
+ return votes[userId] !== undefined ? votes[userId] : null;
445
+ }
446
+ return null;
447
+ }
441
448
 
442
- return votes[userId] !== undefined ? votes[userId] : null; // Return direct vote or null
443
- }
449
+ /**
450
+ * Aggregates votes for a specific hex and topic.
451
+ * @param {string} hexId - The hex identifier.
452
+ * @param {string} topic - The voting topic.
453
+ * @returns {object} - Aggregated vote counts.
454
+ */
455
+ aggregateVotes(hexId, topic) {
456
+ if (!this.hexagonVotes[hexId] || !this.hexagonVotes[hexId][topic]) {
457
+ return {}; // Handle undefined votes
458
+ }
459
+ const votes = this.hexagonVotes[hexId][topic];
460
+ const aggregatedVotes = {};
444
461
 
445
- aggregateVotes(hexId, topic) {
446
- const votes = hexagonVotes[hexId][topic];
447
- const aggregatedVotes = {};
462
+ Object.keys(votes).forEach(userId => {
463
+ const finalVote = this.getFinalVote(userId, topic, votes); // Prefixed with this
464
+ if (finalVote !== null) {
465
+ aggregatedVotes[finalVote] = (aggregatedVotes[finalVote] || 0) + 1;
466
+ }
467
+ });
448
468
 
449
- Object.keys(votes).forEach(userId => {
450
- const finalVote = getFinalVote(userId, topic, votes);
451
- if (finalVote !== null) {
452
- aggregatedVotes[finalVote] = (aggregatedVotes[finalVote] || 0) + 1;
469
+ return aggregatedVotes;
453
470
  }
454
- });
455
471
 
456
- return aggregatedVotes;
457
- }
458
-
459
- async delegateVote(userId, topic, delegateTo) {
472
+ /**
473
+ * Delegates a user's vote to another user.
474
+ * @param {string} userId - The user's identifier.
475
+ * @param {string} topic - The voting topic.
476
+ * @param {string} delegateTo - The user to delegate the vote to.
477
+ */
478
+ async delegateVote(userId, topic, delegateTo) {
460
479
  const response = await fetch('/delegate', {
461
480
  method: 'POST',
462
481
  headers: { 'Content-Type': 'application/json' },
@@ -465,6 +484,13 @@ async delegateVote(userId, topic, delegateTo) {
465
484
  alert(await response.text());
466
485
  }
467
486
 
487
+ /**
488
+ * Casts a vote for a user on a specific topic and hex.
489
+ * @param {string} userId - The user's identifier.
490
+ * @param {string} hexId - The hex identifier.
491
+ * @param {string} topic - The voting topic.
492
+ * @param {string} vote - The vote choice.
493
+ */
468
494
  async vote(userId, hexId, topic, vote) {
469
495
  const response = await fetch('/vote', {
470
496
  method: 'POST',
@@ -475,6 +501,8 @@ async delegateVote(userId, topic, delegateTo) {
475
501
  }
476
502
 
477
503
 
504
+
505
+
478
506
  }
479
507
 
480
508
  export default HoloSphere;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "holosphere",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Holonic Geospatial Communication Infrastructure based on h3.js and gun.js",
5
- "main": "index.js",
5
+ "main": "holosphere.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -11,7 +11,7 @@
11
11
  "license": "GPL-3.0-or-later",
12
12
  "dependencies": {
13
13
  "ajv": "^8.12.0",
14
- "gun": "^0.2020.1239",
14
+ "gun": "^0.2020.1240",
15
15
  "h3-js": "^4.1.0",
16
16
  "openai": "^4.29.2"
17
17
  }