holosphere 1.1.10 → 1.1.12
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/.cursor/rules/futura.mdc +55 -0
- package/FEDERATION.md +17 -17
- package/compute.js +289 -0
- package/content.js +946 -0
- package/examples/federation.js +98 -90
- package/examples/hologram-updates-example.js +106 -0
- package/examples/{references.js → holograms.js} +49 -51
- package/federation.js +427 -245
- package/global.js +725 -0
- package/hologram.js +156 -0
- package/holosphere.d.ts +109 -7
- package/holosphere.js +172 -1565
- package/node.js +240 -0
- package/package.json +2 -5
- package/schema.js +132 -0
- package/test/auth.test.js +55 -37
- package/test/delete.test.js +15 -12
- package/test/federation.test.js +179 -0
- package/test/hologram-deletion.test.js +197 -0
- package/test/hologram-updates-return.test.js +166 -0
- package/test/hologram-updates.test.js +143 -0
- package/test/hologram.test.js +316 -0
- package/test/meta-strip.test.js +159 -0
- package/test/parent-propagation.test.js +138 -0
- package/test/subscription.test.js +105 -70
- package/utils.js +290 -0
- package/test/reference.test.js +0 -211
package/hologram.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// holo_hologram.js
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a soul hologram object for a data item
|
|
5
|
+
* @param {HoloSphere} holoInstance - The HoloSphere instance.
|
|
6
|
+
* @param {string} holon - The holon where the original data is stored
|
|
7
|
+
* @param {string} lens - The lens where the original data is stored
|
|
8
|
+
* @param {object} data - The data to create a hologram for
|
|
9
|
+
* @returns {object} - A hologram object with id and soul
|
|
10
|
+
*/
|
|
11
|
+
export function createHologram(holoInstance, holon, lens, data) {
|
|
12
|
+
// Check if the input data is already a hologram
|
|
13
|
+
if (isHologram(data)) {
|
|
14
|
+
// If it is, just return its existing ID and Soul, ignoring the provided holon/lens
|
|
15
|
+
console.warn('createHologram called with data that is already a hologram. Reusing existing soul:', data.soul);
|
|
16
|
+
return {
|
|
17
|
+
id: data.id,
|
|
18
|
+
soul: data.soul
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Original logic: Input data is not a hologram, create a new soul path
|
|
23
|
+
if (!holon || !lens || !data || !data.id) {
|
|
24
|
+
throw new Error('createHologram: Missing required parameters for non-hologram data');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const soul = `${holoInstance.appname}/${holon}/${lens}/${data.id}`;
|
|
28
|
+
return {
|
|
29
|
+
id: data.id,
|
|
30
|
+
soul: soul
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Parses a soul path into its components.
|
|
36
|
+
* @param {string} soul - The soul path (e.g., "app/holon/lens/key").
|
|
37
|
+
* @returns {object|null} - An object with appname, holon, lens, key, or null if invalid.
|
|
38
|
+
*/
|
|
39
|
+
export function parseSoulPath(soul) {
|
|
40
|
+
if (typeof soul !== 'string') return null;
|
|
41
|
+
const parts = soul.split('/');
|
|
42
|
+
if (parts.length < 4) return null; // Must have at least app/holon/lens/key
|
|
43
|
+
|
|
44
|
+
// Reconstruct key if it contained slashes (though generally disallowed by getNodeRef validation)
|
|
45
|
+
const key = parts.slice(3).join('/');
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
appname: parts[0],
|
|
49
|
+
holon: parts[1],
|
|
50
|
+
lens: parts[2],
|
|
51
|
+
key: key
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Checks if an object is a hologram.
|
|
57
|
+
* This function checks for the presence and type of `id` and `soul` properties,
|
|
58
|
+
* suitable for identifying holograms represented as plain JavaScript objects.
|
|
59
|
+
* It also performs a basic check that the `soul` contains '/' as expected for a path.
|
|
60
|
+
* @param {object | null | undefined} data - The data to check.
|
|
61
|
+
* @returns {boolean} - True if the object is considered a hologram.
|
|
62
|
+
*/
|
|
63
|
+
export function isHologram(data) {
|
|
64
|
+
if (!data || typeof data !== 'object') {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Basic check: Does it have an 'id' and a 'soul' which is a non-empty string?
|
|
69
|
+
if (data.id && typeof data.soul === 'string' && data.soul.length > 0) {
|
|
70
|
+
// Optional stricter check: Does the soul look like a valid path?
|
|
71
|
+
// This prevents objects like { id: 1, soul: "hello" } from being counted.
|
|
72
|
+
// We can use a simplified check here or rely on parseSoulPath failing later.
|
|
73
|
+
if (data.soul.includes('/')) { // Simple check for path structure
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Resolves a hologram to its actual data
|
|
83
|
+
* @param {HoloSphere} holoInstance - The HoloSphere instance.
|
|
84
|
+
* @param {object} hologram - The hologram to resolve
|
|
85
|
+
* @param {object} [options] - Optional parameters
|
|
86
|
+
* @param {boolean} [options.followHolograms=true] - Whether to follow nested holograms
|
|
87
|
+
* @param {Set<string>} [options.visited] - Internal use: Tracks visited souls to prevent loops
|
|
88
|
+
* @returns {Promise<object|null>} - The resolved data, null if resolution failed due to target not found, or the original hologram for circular/invalid cases.
|
|
89
|
+
*/
|
|
90
|
+
export async function resolveHologram(holoInstance, hologram, options = {}) {
|
|
91
|
+
if (!isHologram(hologram)) {
|
|
92
|
+
return hologram; // Not a hologram, return as is
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const { followHolograms = true, visited = new Set() } = options;
|
|
96
|
+
|
|
97
|
+
// Check for circular hologram FIRST
|
|
98
|
+
if (hologram.soul && visited.has(hologram.soul)) {
|
|
99
|
+
console.warn(`!!! CIRCULAR hologram detected for soul: ${hologram.soul}. Returning original hologram.`);
|
|
100
|
+
throw new Error(`CIRCULAR_REFERENCE:${hologram.soul}`);
|
|
101
|
+
} else {
|
|
102
|
+
try {
|
|
103
|
+
// Handle direct soul hologram
|
|
104
|
+
if (hologram.soul) {
|
|
105
|
+
const soulInfo = parseSoulPath(hologram.soul);
|
|
106
|
+
if (!soulInfo) {
|
|
107
|
+
console.warn(`Invalid soul format: ${hologram.soul}`);
|
|
108
|
+
return hologram;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Add current soul to visited set for THIS resolution path
|
|
112
|
+
const nextVisited = new Set(visited);
|
|
113
|
+
nextVisited.add(hologram.soul);
|
|
114
|
+
|
|
115
|
+
console.log(`Resolving hologram with soul: ${hologram.soul}`);
|
|
116
|
+
|
|
117
|
+
// Get original data
|
|
118
|
+
const originalData = await holoInstance.get(
|
|
119
|
+
soulInfo.holon,
|
|
120
|
+
soulInfo.lens,
|
|
121
|
+
soulInfo.key,
|
|
122
|
+
null,
|
|
123
|
+
{
|
|
124
|
+
resolveHolograms: followHolograms,
|
|
125
|
+
visited: nextVisited
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
console.log('### resolveHologram received originalData:', originalData);
|
|
130
|
+
|
|
131
|
+
if (originalData) {
|
|
132
|
+
console.log(`### Returning RESOLVED data for soul: ${hologram.soul}`);
|
|
133
|
+
// Structure for the returned object - isHologram (top-level) is removed
|
|
134
|
+
return {
|
|
135
|
+
...originalData,
|
|
136
|
+
_meta: {
|
|
137
|
+
...(originalData._meta || {}), // Preserve original _meta
|
|
138
|
+
resolvedFromHologram: true, // This is now the primary indicator
|
|
139
|
+
hologramSoul: hologram.soul // Clarified meta field
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
} else {
|
|
143
|
+
console.warn(`!!! Original data NOT FOUND for soul: ${hologram.soul}. Returning null.`);
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
// Should not happen if isHologram() passed
|
|
148
|
+
console.warn('!!! resolveHologram called with object missing soul:', hologram);
|
|
149
|
+
return hologram;
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error(`!!! Error resolving hologram: ${error.message}`, error);
|
|
153
|
+
return hologram; // Return original hologram on error
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
package/holosphere.d.ts
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
* Federation propagation options interface
|
|
3
3
|
*/
|
|
4
4
|
interface PropagationOptions {
|
|
5
|
-
/** Whether to use
|
|
6
|
-
|
|
5
|
+
/** Whether to use holograms instead of duplicating data (default: true) */
|
|
6
|
+
useHolograms?: boolean;
|
|
7
7
|
/** Specific target spaces to propagate to (default: all federated spaces) */
|
|
8
8
|
targetSpaces?: string[];
|
|
9
9
|
/** Password for accessing the source holon (if needed) */
|
|
10
10
|
password?: string | null;
|
|
11
|
+
/** Whether to automatically propagate to parent hexagons (default: true) */
|
|
12
|
+
propagateToParents?: boolean;
|
|
13
|
+
/** Maximum number of parent levels to propagate to (default: 15) */
|
|
14
|
+
maxParentLevels?: number;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
/**
|
|
@@ -18,14 +22,37 @@ interface PutOptions {
|
|
|
18
22
|
autoPropagate?: boolean;
|
|
19
23
|
/** Additional options to pass to propagate */
|
|
20
24
|
propagationOptions?: PropagationOptions;
|
|
25
|
+
/** Whether to disable hologram redirection logic when putting data (default: false) */
|
|
26
|
+
disableHologramRedirection?: boolean;
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
/**
|
|
24
30
|
* Get options interface
|
|
25
31
|
*/
|
|
26
32
|
interface GetOptions {
|
|
27
|
-
/** Whether to automatically resolve
|
|
28
|
-
|
|
33
|
+
/** Whether to automatically resolve holograms (default: true) */
|
|
34
|
+
resolveHolograms?: boolean;
|
|
35
|
+
/** Options passed to the schema validator */
|
|
36
|
+
validationOptions?: object;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolve Hologram options interface
|
|
41
|
+
*/
|
|
42
|
+
interface ResolveHologramOptions {
|
|
43
|
+
/** Whether to follow nested holograms (default: true) */
|
|
44
|
+
followHolograms?: boolean;
|
|
45
|
+
/** Internal use: Tracks visited souls to prevent loops */
|
|
46
|
+
visited?: Set<string>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Represents a Hologram object, typically containing an id and a soul path.
|
|
51
|
+
*/
|
|
52
|
+
interface Hologram {
|
|
53
|
+
id: string;
|
|
54
|
+
soul: string;
|
|
55
|
+
[key: string]: any; // Allow other properties, e.g., _federation
|
|
29
56
|
}
|
|
30
57
|
|
|
31
58
|
/**
|
|
@@ -90,13 +117,44 @@ interface PropagationResult {
|
|
|
90
117
|
error?: string;
|
|
91
118
|
/** Information message if applicable */
|
|
92
119
|
message?: string;
|
|
120
|
+
/** Parent propagation results */
|
|
121
|
+
parentPropagation?: {
|
|
122
|
+
/** Number of successfully propagated items to parents */
|
|
123
|
+
success: number;
|
|
124
|
+
/** Number of errors encountered during parent propagation */
|
|
125
|
+
errors: number;
|
|
126
|
+
/** Number of parent propagations skipped */
|
|
127
|
+
skipped: number;
|
|
128
|
+
/** Messages from parent propagation */
|
|
129
|
+
messages: string[];
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Result from a put operation
|
|
135
|
+
*/
|
|
136
|
+
interface PutResult {
|
|
137
|
+
/** Indicates if the put operation was successful */
|
|
138
|
+
success: boolean;
|
|
139
|
+
/** Indicates if the data ultimately put at the path was a hologram */
|
|
140
|
+
isHologramAtPath?: boolean;
|
|
141
|
+
/** The final holon where data was put (after potential redirection) */
|
|
142
|
+
pathHolon: string;
|
|
143
|
+
/** The final lens where data was put (after potential redirection) */
|
|
144
|
+
pathLens: string;
|
|
145
|
+
/** The final key under which data was put (after potential redirection) */
|
|
146
|
+
pathKey: string;
|
|
147
|
+
/** Result of any automatic propagation, if it occurred */
|
|
148
|
+
propagationResult?: PropagationResult | null;
|
|
149
|
+
/** Error message if the put operation failed at some point */
|
|
150
|
+
error?: string;
|
|
93
151
|
}
|
|
94
152
|
|
|
95
153
|
declare class HoloSphere {
|
|
96
154
|
private appname;
|
|
97
155
|
private strict;
|
|
98
156
|
private validator;
|
|
99
|
-
|
|
157
|
+
public gun;
|
|
100
158
|
private sea;
|
|
101
159
|
private openai?;
|
|
102
160
|
private subscriptions;
|
|
@@ -110,6 +168,12 @@ declare class HoloSphere {
|
|
|
110
168
|
*/
|
|
111
169
|
constructor(appname: string, strict?: boolean, openaikey?: string | null, gunInstance?: any);
|
|
112
170
|
|
|
171
|
+
/**
|
|
172
|
+
* Gets the Gun instance.
|
|
173
|
+
* @returns {any} - The Gun instance.
|
|
174
|
+
*/
|
|
175
|
+
getGun(): any;
|
|
176
|
+
|
|
113
177
|
// ================================ SCHEMA FUNCTIONS ================================
|
|
114
178
|
|
|
115
179
|
/**
|
|
@@ -138,7 +202,7 @@ declare class HoloSphere {
|
|
|
138
202
|
* @param {PutOptions} [options] - Additional options
|
|
139
203
|
* @returns {Promise<any>} - Returns result object if successful
|
|
140
204
|
*/
|
|
141
|
-
put(holon: string, lens: string, data: object, password?: string | null, options?: PutOptions): Promise<
|
|
205
|
+
put(holon: string, lens: string, data: object, password?: string | null, options?: PutOptions): Promise<PutResult>;
|
|
142
206
|
|
|
143
207
|
/**
|
|
144
208
|
* Retrieves content from the specified holon and lens.
|
|
@@ -232,6 +296,32 @@ declare class HoloSphere {
|
|
|
232
296
|
*/
|
|
233
297
|
deleteNode(holon: string, lens: string, key: string): Promise<boolean>;
|
|
234
298
|
|
|
299
|
+
// ================================ HOLOGRAM FUNCTIONS ================================
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Creates a soul hologram object for a data item.
|
|
303
|
+
* @param {string} holon - The holon where the original data is stored.
|
|
304
|
+
* @param {string} lens - The lens where the original data is stored.
|
|
305
|
+
* @param {object} data - The data to create a hologram for. Must have an 'id' field.
|
|
306
|
+
* @returns {Hologram} - A hologram object containing id and soul.
|
|
307
|
+
*/
|
|
308
|
+
createHologram(holon: string, lens: string, data: { id: string, [key: string]: any }): Hologram;
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Checks if an object is a hologram (has id and soul).
|
|
312
|
+
* @param {any} data - The data to check.
|
|
313
|
+
* @returns {boolean} - True if the object is considered a hologram.
|
|
314
|
+
*/
|
|
315
|
+
isHologram(data: any): data is Hologram;
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Resolves a hologram to its actual data by following its soul path.
|
|
319
|
+
* @param {Hologram} hologram - The hologram object to resolve.
|
|
320
|
+
* @param {ResolveHologramOptions} [options] - Options for resolution.
|
|
321
|
+
* @returns {Promise<object|null>} - The resolved data, null if not found, or the original hologram in case of loops/errors.
|
|
322
|
+
*/
|
|
323
|
+
resolveHologram(hologram: Hologram, options?: ResolveHologramOptions): Promise<object | null>;
|
|
324
|
+
|
|
235
325
|
// ================================ GLOBAL FUNCTIONS ================================
|
|
236
326
|
|
|
237
327
|
/**
|
|
@@ -364,9 +454,12 @@ declare class HoloSphere {
|
|
|
364
454
|
* @param {string} [password1] - Optional password for the first holon
|
|
365
455
|
* @param {string} [password2] - Optional password for the second holon
|
|
366
456
|
* @param {boolean} [bidirectional=true] - Whether to set up bidirectional notifications automatically
|
|
457
|
+
* @param {object} [lensConfig] - Optional lens-specific configuration
|
|
458
|
+
* @param {string[]} [lensConfig.federate] - List of lenses to federate (default: all)
|
|
459
|
+
* @param {string[]} [lensConfig.notify] - List of lenses to notify (default: all)
|
|
367
460
|
* @returns {Promise<boolean>} - True if federation was created successfully
|
|
368
461
|
*/
|
|
369
|
-
federate(holonId1: string, holonId2: string, password1?: string | null, password2?: string | null, bidirectional?: boolean): Promise<boolean>;
|
|
462
|
+
federate(holonId1: string, holonId2: string, password1?: string | null, password2?: string | null, bidirectional?: boolean, lensConfig?: { federate?: string[], notify?: string[] }): Promise<boolean>;
|
|
370
463
|
|
|
371
464
|
/**
|
|
372
465
|
* Subscribes to federation notifications for a holon
|
|
@@ -386,6 +479,15 @@ declare class HoloSphere {
|
|
|
386
479
|
*/
|
|
387
480
|
getFederation(holonId: string, password?: string | null): Promise<FederationInfo | null>;
|
|
388
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Retrieves the lens-specific configuration for a federation link between two holons.
|
|
484
|
+
* @param {string} holonId - The ID of the source holon.
|
|
485
|
+
* @param {string} targetHolonId - The ID of the target holon in the federation link.
|
|
486
|
+
* @param {string} [password] - Optional password for the source holon.
|
|
487
|
+
* @returns {Promise<{ federate: string[], notify: string[] } | null>} - An object with 'federate' and 'notify' arrays, or null if not found.
|
|
488
|
+
*/
|
|
489
|
+
getFederatedConfig(holonId: string, targetHolonId: string, password?: string | null): Promise<{ federate: string[], notify: string[] } | null>;
|
|
490
|
+
|
|
389
491
|
/**
|
|
390
492
|
* Removes a federation relationship between holons
|
|
391
493
|
* @param {string} holonId1 - The first holon ID
|