holosphere 1.1.9 → 1.1.11

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/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,8 +2,8 @@
2
2
  * Federation propagation options interface
3
3
  */
4
4
  interface PropagationOptions {
5
- /** Whether to use references instead of duplicating data (default: true) */
6
- useReferences?: boolean;
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) */
@@ -18,14 +18,37 @@ interface PutOptions {
18
18
  autoPropagate?: boolean;
19
19
  /** Additional options to pass to propagate */
20
20
  propagationOptions?: PropagationOptions;
21
+ /** Whether to disable hologram redirection logic when putting data (default: false) */
22
+ disableHologramRedirection?: boolean;
21
23
  }
22
24
 
23
25
  /**
24
26
  * Get options interface
25
27
  */
26
28
  interface GetOptions {
27
- /** Whether to automatically resolve federation references (default: true) */
28
- resolveReferences?: boolean;
29
+ /** Whether to automatically resolve holograms (default: true) */
30
+ resolveHolograms?: boolean;
31
+ /** Options passed to the schema validator */
32
+ validationOptions?: object;
33
+ }
34
+
35
+ /**
36
+ * Resolve Hologram options interface
37
+ */
38
+ interface ResolveHologramOptions {
39
+ /** Whether to follow nested holograms (default: true) */
40
+ followHolograms?: boolean;
41
+ /** Internal use: Tracks visited souls to prevent loops */
42
+ visited?: Set<string>;
43
+ }
44
+
45
+ /**
46
+ * Represents a Hologram object, typically containing an id and a soul path.
47
+ */
48
+ interface Hologram {
49
+ id: string;
50
+ soul: string;
51
+ [key: string]: any; // Allow other properties, e.g., _federation
29
52
  }
30
53
 
31
54
  /**
@@ -92,11 +115,31 @@ interface PropagationResult {
92
115
  message?: string;
93
116
  }
94
117
 
118
+ /**
119
+ * Result from a put operation
120
+ */
121
+ interface PutResult {
122
+ /** Indicates if the put operation was successful */
123
+ success: boolean;
124
+ /** Indicates if the data ultimately put at the path was a hologram */
125
+ isHologramAtPath?: boolean;
126
+ /** The final holon where data was put (after potential redirection) */
127
+ pathHolon: string;
128
+ /** The final lens where data was put (after potential redirection) */
129
+ pathLens: string;
130
+ /** The final key under which data was put (after potential redirection) */
131
+ pathKey: string;
132
+ /** Result of any automatic propagation, if it occurred */
133
+ propagationResult?: PropagationResult | null;
134
+ /** Error message if the put operation failed at some point */
135
+ error?: string;
136
+ }
137
+
95
138
  declare class HoloSphere {
96
139
  private appname;
97
140
  private strict;
98
141
  private validator;
99
- private gun;
142
+ public gun;
100
143
  private sea;
101
144
  private openai?;
102
145
  private subscriptions;
@@ -110,6 +153,12 @@ declare class HoloSphere {
110
153
  */
111
154
  constructor(appname: string, strict?: boolean, openaikey?: string | null, gunInstance?: any);
112
155
 
156
+ /**
157
+ * Gets the Gun instance.
158
+ * @returns {any} - The Gun instance.
159
+ */
160
+ getGun(): any;
161
+
113
162
  // ================================ SCHEMA FUNCTIONS ================================
114
163
 
115
164
  /**
@@ -138,7 +187,7 @@ declare class HoloSphere {
138
187
  * @param {PutOptions} [options] - Additional options
139
188
  * @returns {Promise<any>} - Returns result object if successful
140
189
  */
141
- put(holon: string, lens: string, data: object, password?: string | null, options?: PutOptions): Promise<any>;
190
+ put(holon: string, lens: string, data: object, password?: string | null, options?: PutOptions): Promise<PutResult>;
142
191
 
143
192
  /**
144
193
  * Retrieves content from the specified holon and lens.
@@ -232,6 +281,32 @@ declare class HoloSphere {
232
281
  */
233
282
  deleteNode(holon: string, lens: string, key: string): Promise<boolean>;
234
283
 
284
+ // ================================ HOLOGRAM FUNCTIONS ================================
285
+
286
+ /**
287
+ * Creates a soul hologram object for a data item.
288
+ * @param {string} holon - The holon where the original data is stored.
289
+ * @param {string} lens - The lens where the original data is stored.
290
+ * @param {object} data - The data to create a hologram for. Must have an 'id' field.
291
+ * @returns {Hologram} - A hologram object containing id and soul.
292
+ */
293
+ createHologram(holon: string, lens: string, data: { id: string, [key: string]: any }): Hologram;
294
+
295
+ /**
296
+ * Checks if an object is a hologram (has id and soul).
297
+ * @param {any} data - The data to check.
298
+ * @returns {boolean} - True if the object is considered a hologram.
299
+ */
300
+ isHologram(data: any): data is Hologram;
301
+
302
+ /**
303
+ * Resolves a hologram to its actual data by following its soul path.
304
+ * @param {Hologram} hologram - The hologram object to resolve.
305
+ * @param {ResolveHologramOptions} [options] - Options for resolution.
306
+ * @returns {Promise<object|null>} - The resolved data, null if not found, or the original hologram in case of loops/errors.
307
+ */
308
+ resolveHologram(hologram: Hologram, options?: ResolveHologramOptions): Promise<object | null>;
309
+
235
310
  // ================================ GLOBAL FUNCTIONS ================================
236
311
 
237
312
  /**
@@ -364,9 +439,12 @@ declare class HoloSphere {
364
439
  * @param {string} [password1] - Optional password for the first holon
365
440
  * @param {string} [password2] - Optional password for the second holon
366
441
  * @param {boolean} [bidirectional=true] - Whether to set up bidirectional notifications automatically
442
+ * @param {object} [lensConfig] - Optional lens-specific configuration
443
+ * @param {string[]} [lensConfig.federate] - List of lenses to federate (default: all)
444
+ * @param {string[]} [lensConfig.notify] - List of lenses to notify (default: all)
367
445
  * @returns {Promise<boolean>} - True if federation was created successfully
368
446
  */
369
- federate(holonId1: string, holonId2: string, password1?: string | null, password2?: string | null, bidirectional?: boolean): Promise<boolean>;
447
+ federate(holonId1: string, holonId2: string, password1?: string | null, password2?: string | null, bidirectional?: boolean, lensConfig?: { federate?: string[], notify?: string[] }): Promise<boolean>;
370
448
 
371
449
  /**
372
450
  * Subscribes to federation notifications for a holon
@@ -386,6 +464,15 @@ declare class HoloSphere {
386
464
  */
387
465
  getFederation(holonId: string, password?: string | null): Promise<FederationInfo | null>;
388
466
 
467
+ /**
468
+ * Retrieves the lens-specific configuration for a federation link between two holons.
469
+ * @param {string} holonId - The ID of the source holon.
470
+ * @param {string} targetHolonId - The ID of the target holon in the federation link.
471
+ * @param {string} [password] - Optional password for the source holon.
472
+ * @returns {Promise<{ federate: string[], notify: string[] } | null>} - An object with 'federate' and 'notify' arrays, or null if not found.
473
+ */
474
+ getFederatedConfig(holonId: string, targetHolonId: string, password?: string | null): Promise<{ federate: string[], notify: string[] } | null>;
475
+
389
476
  /**
390
477
  * Removes a federation relationship between holons
391
478
  * @param {string} holonId1 - The first holon ID