holosphere 2.0.0-alpha10 → 2.0.0-alpha12

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.
Files changed (62) hide show
  1. package/dist/{2019-D2OG2idw.js → 2019-DQdDE6DG.js} +2 -2
  2. package/dist/{2019-D2OG2idw.js.map → 2019-DQdDE6DG.js.map} +1 -1
  3. package/dist/{2019-EION3wKo.cjs → 2019-Ew-DTDlI.cjs} +2 -2
  4. package/dist/{2019-EION3wKo.cjs.map → 2019-Ew-DTDlI.cjs.map} +1 -1
  5. package/dist/{browser-BSniCNqO.js → browser-CckFyRI9.js} +2 -2
  6. package/dist/{browser-BSniCNqO.js.map → browser-CckFyRI9.js.map} +1 -1
  7. package/dist/browser-D2qtVhH5.cjs +2 -0
  8. package/dist/{browser-Cq59Ij19.cjs.map → browser-D2qtVhH5.cjs.map} +1 -1
  9. package/dist/cjs/holosphere.cjs +1 -1
  10. package/dist/esm/holosphere.js +67 -50
  11. package/dist/index-9sqetkAn.cjs +29 -0
  12. package/dist/index-9sqetkAn.cjs.map +1 -0
  13. package/dist/index-C0ITDyFo.cjs +13 -0
  14. package/dist/index-C0ITDyFo.cjs.map +1 -0
  15. package/dist/{index-DeZ1xz_s.js → index-DrYM1LOY.js} +2 -2
  16. package/dist/{index-DeZ1xz_s.js.map → index-DrYM1LOY.js.map} +1 -1
  17. package/dist/{index-DJXftyvB.js → index-TDDyakLc.js} +20345 -805
  18. package/dist/index-TDDyakLc.js.map +1 -0
  19. package/dist/{index-DDGt_V9o.cjs → index-kyf1sjaC.cjs} +3 -3
  20. package/dist/{index-DDGt_V9o.cjs.map → index-kyf1sjaC.cjs.map} +1 -1
  21. package/dist/index-lbSQUoRz.js +11663 -0
  22. package/dist/index-lbSQUoRz.js.map +1 -0
  23. package/dist/{indexeddb-storage-BFt6hMeF.js → indexeddb-storage-CXhjqwhA.js} +2 -2
  24. package/dist/{indexeddb-storage-BFt6hMeF.js.map → indexeddb-storage-CXhjqwhA.js.map} +1 -1
  25. package/dist/{indexeddb-storage-BK5tv4Sh.cjs → indexeddb-storage-DFESDYIj.cjs} +2 -2
  26. package/dist/{indexeddb-storage-BK5tv4Sh.cjs.map → indexeddb-storage-DFESDYIj.cjs.map} +1 -1
  27. package/dist/{memory-storage-Dao7jfYG.cjs → memory-storage-D1tc1bjk.cjs} +2 -2
  28. package/dist/{memory-storage-Dao7jfYG.cjs.map → memory-storage-D1tc1bjk.cjs.map} +1 -1
  29. package/dist/{memory-storage-C9HuoL2E.js → memory-storage-DkewsdcM.js} +2 -2
  30. package/dist/{memory-storage-C9HuoL2E.js.map → memory-storage-DkewsdcM.js.map} +1 -1
  31. package/docs/FEDERATION.md +474 -0
  32. package/package.json +3 -1
  33. package/src/crypto/nostr-utils.js +7 -0
  34. package/src/crypto/secp256k1.js +46 -29
  35. package/src/federation/capabilities.js +162 -0
  36. package/src/federation/card-storage.js +304 -0
  37. package/src/federation/handshake.js +204 -7
  38. package/src/federation/hologram.js +167 -58
  39. package/src/federation/holon-registry.js +166 -0
  40. package/src/federation/index.js +68 -0
  41. package/src/federation/registry.js +110 -2
  42. package/src/federation/request-card.js +373 -0
  43. package/src/hierarchical/upcast.js +19 -3
  44. package/src/index.js +224 -95
  45. package/src/lib/federation-methods.js +527 -5
  46. package/src/storage/nostr-async.js +2 -2
  47. package/src/storage/nostr-client.js +370 -155
  48. package/src/storage/nostr-wrapper.js +1 -1
  49. package/dist/_commonjsHelpers-C37NGDzP.cjs +0 -2
  50. package/dist/_commonjsHelpers-C37NGDzP.cjs.map +0 -1
  51. package/dist/_commonjsHelpers-CUmg6egw.js +0 -7
  52. package/dist/_commonjsHelpers-CUmg6egw.js.map +0 -1
  53. package/dist/browser-Cq59Ij19.cjs +0 -2
  54. package/dist/cdn/holosphere.min.js +0 -55
  55. package/dist/cdn/holosphere.min.js.map +0 -1
  56. package/dist/index-DJXftyvB.js.map +0 -1
  57. package/dist/index-DMbdcMtK.cjs +0 -18
  58. package/dist/index-DMbdcMtK.cjs.map +0 -1
  59. package/dist/secp256k1-BbKzbLtD.cjs +0 -12
  60. package/dist/secp256k1-BbKzbLtD.cjs.map +0 -1
  61. package/dist/secp256k1-CreY7Pcl.js +0 -1890
  62. package/dist/secp256k1-CreY7Pcl.js.map +0 -1
@@ -0,0 +1,373 @@
1
+ /**
2
+ * @fileoverview Federation Request Card Configuration
3
+ *
4
+ * Provides a card-based configuration system for federation requests.
5
+ * After inputting a public key, displays a card with all available lenses
6
+ * that can be configured for the federation request.
7
+ *
8
+ * @module federation/request-card
9
+ */
10
+
11
+ import { issueCapabilitiesForLenses } from './capabilities.js';
12
+
13
+ /**
14
+ * @typedef {Object} LensConfig
15
+ * @property {string} name - Lens name
16
+ * @property {boolean} enabled - Whether lens is enabled for federation
17
+ * @property {string} direction - 'inbound', 'outbound', or 'bidirectional'
18
+ * @property {string[]} permissions - Permissions to grant ('read', 'write')
19
+ */
20
+
21
+ /**
22
+ * @typedef {Object} FederationCardConfig
23
+ * @property {string} partnerPubKey - Partner's public key
24
+ * @property {string} partnerName - Partner's display name (optional)
25
+ * @property {string} holonId - Local holon ID
26
+ * @property {string} holonName - Local holon display name
27
+ * @property {LensConfig[]} lenses - Lens configurations
28
+ * @property {string} message - Optional message to partner
29
+ * @property {number} createdAt - Card creation timestamp
30
+ * @property {string} status - 'pending', 'sent', 'accepted', 'rejected', 'dismissed'
31
+ */
32
+
33
+ /**
34
+ * @typedef {Object} CardDisplayOptions
35
+ * @property {number} initialLensCount - Number of lenses to show initially (default: 3)
36
+ * @property {boolean} expanded - Whether card is expanded to show all lenses
37
+ * @property {boolean} showPermissions - Whether to show permission toggles
38
+ */
39
+
40
+ // Default number of lenses to show before "Show more" button
41
+ const DEFAULT_INITIAL_LENS_COUNT = 3;
42
+
43
+ /**
44
+ * Create a federation request card configuration
45
+ * @param {Object} params - Card parameters
46
+ * @param {string} params.partnerPubKey - Partner's public key
47
+ * @param {string} params.partnerName - Partner's display name
48
+ * @param {string} params.holonId - Local holon ID
49
+ * @param {string} params.holonName - Local holon display name
50
+ * @param {string[]} params.availableLenses - All available lens names
51
+ * @param {Object} params.defaultConfig - Default lens configuration
52
+ * @returns {FederationCardConfig} Card configuration
53
+ */
54
+ export function createFederationCard({
55
+ partnerPubKey,
56
+ partnerName = null,
57
+ holonId,
58
+ holonName,
59
+ availableLenses = [],
60
+ defaultConfig = {},
61
+ }) {
62
+ const {
63
+ defaultDirection = 'bidirectional',
64
+ defaultPermissions = ['read'],
65
+ enabledByDefault = true,
66
+ } = defaultConfig;
67
+
68
+ // Create lens configurations for all available lenses
69
+ const lenses = availableLenses.map(name => ({
70
+ name,
71
+ enabled: enabledByDefault,
72
+ direction: defaultDirection,
73
+ permissions: [...defaultPermissions],
74
+ }));
75
+
76
+ return {
77
+ id: `fedcard_${partnerPubKey.substring(0, 8)}_${Date.now()}`,
78
+ partnerPubKey,
79
+ partnerName,
80
+ holonId,
81
+ holonName,
82
+ lenses,
83
+ message: '',
84
+ createdAt: Date.now(),
85
+ status: 'pending',
86
+ expanded: false,
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Update a lens configuration in a card
92
+ * @param {FederationCardConfig} card - Card configuration
93
+ * @param {string} lensName - Lens name to update
94
+ * @param {Partial<LensConfig>} updates - Updates to apply
95
+ * @returns {FederationCardConfig} Updated card
96
+ */
97
+ export function updateLensConfig(card, lensName, updates) {
98
+ const lensIndex = card.lenses.findIndex(l => l.name === lensName);
99
+ if (lensIndex === -1) return card;
100
+
101
+ const updatedLenses = [...card.lenses];
102
+ updatedLenses[lensIndex] = {
103
+ ...updatedLenses[lensIndex],
104
+ ...updates,
105
+ };
106
+
107
+ return {
108
+ ...card,
109
+ lenses: updatedLenses,
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Toggle a lens enabled/disabled state
115
+ * @param {FederationCardConfig} card - Card configuration
116
+ * @param {string} lensName - Lens name to toggle
117
+ * @returns {FederationCardConfig} Updated card
118
+ */
119
+ export function toggleLens(card, lensName) {
120
+ const lens = card.lenses.find(l => l.name === lensName);
121
+ if (!lens) return card;
122
+
123
+ return updateLensConfig(card, lensName, { enabled: !lens.enabled });
124
+ }
125
+
126
+ /**
127
+ * Enable all lenses in a card
128
+ * @param {FederationCardConfig} card - Card configuration
129
+ * @returns {FederationCardConfig} Updated card
130
+ */
131
+ export function enableAllLenses(card) {
132
+ return {
133
+ ...card,
134
+ lenses: card.lenses.map(l => ({ ...l, enabled: true })),
135
+ };
136
+ }
137
+
138
+ /**
139
+ * Disable all lenses in a card
140
+ * @param {FederationCardConfig} card - Card configuration
141
+ * @returns {FederationCardConfig} Updated card
142
+ */
143
+ export function disableAllLenses(card) {
144
+ return {
145
+ ...card,
146
+ lenses: card.lenses.map(l => ({ ...l, enabled: false })),
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Toggle card expansion to show all lenses
152
+ * @param {FederationCardConfig} card - Card configuration
153
+ * @returns {FederationCardConfig} Updated card
154
+ */
155
+ export function toggleCardExpansion(card) {
156
+ return {
157
+ ...card,
158
+ expanded: !card.expanded,
159
+ };
160
+ }
161
+
162
+ /**
163
+ * Get lenses to display based on expansion state
164
+ * @param {FederationCardConfig} card - Card configuration
165
+ * @param {number} initialCount - Number of lenses to show when collapsed
166
+ * @returns {Object} { visibleLenses, hiddenCount, isExpanded }
167
+ */
168
+ export function getVisibleLenses(card, initialCount = DEFAULT_INITIAL_LENS_COUNT) {
169
+ const allLenses = card.lenses;
170
+ const isExpanded = card.expanded;
171
+
172
+ if (isExpanded || allLenses.length <= initialCount) {
173
+ return {
174
+ visibleLenses: allLenses,
175
+ hiddenCount: 0,
176
+ isExpanded: true,
177
+ };
178
+ }
179
+
180
+ return {
181
+ visibleLenses: allLenses.slice(0, initialCount),
182
+ hiddenCount: allLenses.length - initialCount,
183
+ isExpanded: false,
184
+ };
185
+ }
186
+
187
+ /**
188
+ * Get enabled lenses from a card
189
+ * @param {FederationCardConfig} card - Card configuration
190
+ * @returns {LensConfig[]} Enabled lenses
191
+ */
192
+ export function getEnabledLenses(card) {
193
+ return card.lenses.filter(l => l.enabled);
194
+ }
195
+
196
+ /**
197
+ * Get lens configuration for handshake (inbound/outbound arrays)
198
+ * @param {FederationCardConfig} card - Card configuration
199
+ * @returns {Object} { inbound: string[], outbound: string[] }
200
+ */
201
+ export function getLensConfigForHandshake(card) {
202
+ const inbound = [];
203
+ const outbound = [];
204
+
205
+ for (const lens of card.lenses) {
206
+ if (!lens.enabled) continue;
207
+
208
+ if (lens.direction === 'inbound' || lens.direction === 'bidirectional') {
209
+ inbound.push(lens.name);
210
+ }
211
+ if (lens.direction === 'outbound' || lens.direction === 'bidirectional') {
212
+ outbound.push(lens.name);
213
+ }
214
+ }
215
+
216
+ return { inbound, outbound };
217
+ }
218
+
219
+ /**
220
+ * Update card status
221
+ * @param {FederationCardConfig} card - Card configuration
222
+ * @param {string} status - New status
223
+ * @returns {FederationCardConfig} Updated card
224
+ */
225
+ export function updateCardStatus(card, status) {
226
+ return {
227
+ ...card,
228
+ status,
229
+ updatedAt: Date.now(),
230
+ };
231
+ }
232
+
233
+ /**
234
+ * Dismiss a card (mark as dismissed so it doesn't reappear)
235
+ * @param {FederationCardConfig} card - Card configuration
236
+ * @returns {FederationCardConfig} Updated card with dismissed status
237
+ */
238
+ export function dismissCard(card) {
239
+ return updateCardStatus(card, 'dismissed');
240
+ }
241
+
242
+ /**
243
+ * Check if a card should be displayed
244
+ * @param {FederationCardConfig} card - Card configuration
245
+ * @returns {boolean} True if card should be displayed
246
+ */
247
+ export function shouldDisplayCard(card) {
248
+ return card.status !== 'dismissed' && card.status !== 'rejected';
249
+ }
250
+
251
+ /**
252
+ * Convert card configuration to handshake request params
253
+ * @param {FederationCardConfig} card - Card configuration
254
+ * @returns {Object} Params for initiateFederationHandshake
255
+ */
256
+ export function cardToHandshakeParams(card) {
257
+ const lensConfig = getLensConfigForHandshake(card);
258
+
259
+ return {
260
+ partnerPubKey: card.partnerPubKey,
261
+ holonId: card.holonId,
262
+ holonName: card.holonName,
263
+ lensConfig,
264
+ message: card.message,
265
+ };
266
+ }
267
+
268
+ /**
269
+ * Generate capabilities for a card's outbound lenses
270
+ * @param {Object} client - NostrClient instance
271
+ * @param {FederationCardConfig} card - Card configuration
272
+ * @returns {Promise<Object[]>} Array of capability info objects
273
+ */
274
+ export async function generateCapabilitiesForCard(client, card) {
275
+ const { outbound } = getLensConfigForHandshake(card);
276
+
277
+ if (outbound.length === 0) {
278
+ return [];
279
+ }
280
+
281
+ return issueCapabilitiesForLenses(
282
+ client,
283
+ card.holonId,
284
+ outbound,
285
+ card.partnerPubKey,
286
+ { permissions: ['read'] }
287
+ );
288
+ }
289
+
290
+ /**
291
+ * Render card as a simple text representation (for CLI/logs)
292
+ * @param {FederationCardConfig} card - Card configuration
293
+ * @param {CardDisplayOptions} options - Display options
294
+ * @returns {string} Text representation
295
+ */
296
+ export function renderCardAsText(card, options = {}) {
297
+ const { initialLensCount = DEFAULT_INITIAL_LENS_COUNT } = options;
298
+ const { visibleLenses, hiddenCount, isExpanded } = getVisibleLenses(card, initialLensCount);
299
+ const { inbound, outbound } = getLensConfigForHandshake(card);
300
+
301
+ const lines = [
302
+ `┌─────────────────────────────────────────────────────┐`,
303
+ `│ Federation Request │`,
304
+ `├─────────────────────────────────────────────────────┤`,
305
+ `│ Partner: ${(card.partnerName || card.partnerPubKey.substring(0, 16) + '...').padEnd(40)}│`,
306
+ `│ Status: ${card.status.padEnd(40)}│`,
307
+ `├─────────────────────────────────────────────────────┤`,
308
+ `│ Lenses: │`,
309
+ ];
310
+
311
+ for (const lens of visibleLenses) {
312
+ const status = lens.enabled ? '✓' : '○';
313
+ const dir = lens.direction === 'bidirectional' ? '↔' :
314
+ lens.direction === 'inbound' ? '←' : '→';
315
+ lines.push(`│ ${status} ${lens.name.padEnd(20)} ${dir.padEnd(22)}│`);
316
+ }
317
+
318
+ if (hiddenCount > 0) {
319
+ lines.push(`│ ... and ${hiddenCount} more lenses (click to expand) │`);
320
+ }
321
+
322
+ lines.push(`├─────────────────────────────────────────────────────┤`);
323
+ lines.push(`│ Sharing: ${outbound.length} lenses | Receiving: ${inbound.length} lenses`.padEnd(52) + `│`);
324
+ lines.push(`└─────────────────────────────────────────────────────┘`);
325
+
326
+ return lines.join('\n');
327
+ }
328
+
329
+ /**
330
+ * Serialize card for storage
331
+ * @param {FederationCardConfig} card - Card configuration
332
+ * @returns {Object} Serialized card
333
+ */
334
+ export function serializeCard(card) {
335
+ return {
336
+ ...card,
337
+ serializedAt: Date.now(),
338
+ };
339
+ }
340
+
341
+ /**
342
+ * Deserialize card from storage
343
+ * @param {Object} data - Serialized card data
344
+ * @returns {FederationCardConfig} Card configuration
345
+ */
346
+ export function deserializeCard(data) {
347
+ return {
348
+ ...data,
349
+ expanded: data.expanded || false,
350
+ lenses: data.lenses || [],
351
+ };
352
+ }
353
+
354
+ export default {
355
+ createFederationCard,
356
+ updateLensConfig,
357
+ toggleLens,
358
+ enableAllLenses,
359
+ disableAllLenses,
360
+ toggleCardExpansion,
361
+ getVisibleLenses,
362
+ getEnabledLenses,
363
+ getLensConfigForHandshake,
364
+ updateCardStatus,
365
+ dismissCard,
366
+ shouldDisplayCard,
367
+ cardToHandshakeParams,
368
+ generateCapabilitiesForCard,
369
+ renderCardAsText,
370
+ serializeCard,
371
+ deserializeCard,
372
+ DEFAULT_INITIAL_LENS_COUNT,
373
+ };
@@ -1,11 +1,14 @@
1
1
  /**
2
2
  * @fileoverview Hierarchical aggregation (upcast) operations for propagating data to parent holons.
3
3
  * Implements upcast operations (FR-025 to FR-027) for H3-based geographic hierarchies.
4
+ *
5
+ * UNIFIED MODEL: Uses createHologramWithCapability for consistent capability-based federation.
6
+ *
4
7
  * @module hierarchical/upcast
5
8
  */
6
9
 
7
10
  import { getParents, isValidH3 } from '../spatial/h3-operations.js';
8
- import { createHologram } from '../federation/hologram.js';
11
+ import { createHologramWithCapability } from '../federation/hologram.js';
9
12
  import { write } from '../storage/unified-storage.js';
10
13
 
11
14
  /**
@@ -50,6 +53,7 @@ export async function upcast(hs, holonId, lensName, dataId, options = {}) {
50
53
 
51
54
  /**
52
55
  * Propagate data to a parent holon by creating a hologram reference.
56
+ * UNIFIED MODEL: Uses createHologramWithCapability for consistent capability-based federation.
53
57
  * @private
54
58
  * @param {Object} client - Nostr client instance
55
59
  * @param {string} appname - Application name
@@ -69,8 +73,20 @@ async function propagateToParent(
69
73
  dataId,
70
74
  operation
71
75
  ) {
72
- // Create hologram reference
73
- const hologram = createHologram(sourceHolon, parentHolon, lensName, dataId, appname);
76
+ // UNIFIED MODEL: Create hologram with capability
77
+ const hologram = await createHologramWithCapability(
78
+ client,
79
+ sourceHolon,
80
+ parentHolon,
81
+ lensName,
82
+ dataId,
83
+ appname,
84
+ {
85
+ // Use client's public key as source author (self-federation for upcast)
86
+ sourceAuthorPubKey: client.publicKey,
87
+ permissions: ['read'],
88
+ }
89
+ );
74
90
 
75
91
  // Add operation metadata
76
92
  hologram._meta.operation = operation;