holosphere 2.0.0-alpha11 → 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 (60) 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-Bl6rM1NW.js → index-DrYM1LOY.js} +2 -2
  16. package/dist/{index-Bl6rM1NW.js.map → index-DrYM1LOY.js.map} +1 -1
  17. package/dist/{index-D-jZhliX.js → index-TDDyakLc.js} +19827 -720
  18. package/dist/index-TDDyakLc.js.map +1 -0
  19. package/dist/{index-Bwg3OzRM.cjs → index-kyf1sjaC.cjs} +3 -3
  20. package/dist/{index-Bwg3OzRM.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-5eiUNsHC.js → indexeddb-storage-CXhjqwhA.js} +2 -2
  24. package/dist/{indexeddb-storage-5eiUNsHC.js.map → indexeddb-storage-CXhjqwhA.js.map} +1 -1
  25. package/dist/{indexeddb-storage-FNFUVvTJ.cjs → indexeddb-storage-DFESDYIj.cjs} +2 -2
  26. package/dist/{indexeddb-storage-FNFUVvTJ.cjs.map → indexeddb-storage-DFESDYIj.cjs.map} +1 -1
  27. package/dist/{memory-storage-DMt36uZO.cjs → memory-storage-D1tc1bjk.cjs} +2 -2
  28. package/dist/{memory-storage-DMt36uZO.cjs.map → memory-storage-D1tc1bjk.cjs.map} +1 -1
  29. package/dist/{memory-storage-CI-gfmuG.js → memory-storage-DkewsdcM.js} +2 -2
  30. package/dist/{memory-storage-CI-gfmuG.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 +162 -76
  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/index-D-jZhliX.js.map +0 -1
  55. package/dist/index-Dc6Z8Aob.cjs +0 -18
  56. package/dist/index-Dc6Z8Aob.cjs.map +0 -1
  57. package/dist/secp256k1-CEwJNcfV.js +0 -1890
  58. package/dist/secp256k1-CEwJNcfV.js.map +0 -1
  59. package/dist/secp256k1-CiEONUnj.cjs +0 -12
  60. package/dist/secp256k1-CiEONUnj.cjs.map +0 -1
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Holon Registry - Maps holonId to public key
3
+ *
4
+ * Every holon (H3 cell, telegram chat, concept) can be registered with a keypair.
5
+ * The holonId IS the public key (or resolves to one via this registry).
6
+ *
7
+ * When reading data, the system resolves holonId -> pubkey to determine
8
+ * whose data to read and what capabilities are needed.
9
+ */
10
+
11
+ import { writeGlobal, readGlobal, getAllGlobal } from '../storage/global-tables.js';
12
+
13
+ const HOLON_REGISTRY_TABLE = '_holon-registry';
14
+
15
+ /**
16
+ * Check if a string is a valid 64-character hex public key
17
+ * @param {string} str - String to check
18
+ * @returns {boolean} True if valid pubkey format
19
+ */
20
+ export function isPubkey(str) {
21
+ return typeof str === 'string' && /^[0-9a-f]{64}$/i.test(str);
22
+ }
23
+
24
+ /**
25
+ * Register a holon -> public key mapping
26
+ * @param {Object} client - NostrClient instance
27
+ * @param {string} appname - Application namespace
28
+ * @param {string} holonId - Holon identifier (H3, chatId, concept, etc.)
29
+ * @param {string} publicKey - 64-char hex public key
30
+ * @param {Object} options - Registration options
31
+ * @param {string} [options.alias] - Human-readable name
32
+ * @returns {Promise<boolean>} Success indicator
33
+ */
34
+ export async function registerHolon(client, appname, holonId, publicKey, options = {}) {
35
+ if (!isPubkey(publicKey)) {
36
+ throw new Error(`Invalid public key format: ${publicKey}`);
37
+ }
38
+
39
+ // Don't register if holonId is already a pubkey
40
+ if (isPubkey(holonId)) {
41
+ return true; // No registration needed
42
+ }
43
+
44
+ const entry = {
45
+ id: holonId,
46
+ holonId: holonId,
47
+ publicKey: publicKey,
48
+ alias: options.alias || null,
49
+ createdAt: Date.now(),
50
+ updatedAt: Date.now(),
51
+ createdBy: client.publicKey,
52
+ };
53
+
54
+ return writeGlobal(client, appname, HOLON_REGISTRY_TABLE, entry);
55
+ }
56
+
57
+ /**
58
+ * Look up a holon's registration entry
59
+ * @param {Object} client - NostrClient instance
60
+ * @param {string} appname - Application namespace
61
+ * @param {string} holonId - Holon identifier
62
+ * @returns {Promise<Object|null>} Registry entry or null
63
+ */
64
+ export async function lookupHolon(client, appname, holonId) {
65
+ // If already a pubkey, return synthetic entry
66
+ if (isPubkey(holonId)) {
67
+ return {
68
+ holonId: holonId,
69
+ publicKey: holonId,
70
+ isDirect: true,
71
+ };
72
+ }
73
+
74
+ return readGlobal(client, appname, HOLON_REGISTRY_TABLE, holonId);
75
+ }
76
+
77
+ /**
78
+ * Resolve holonId to public key
79
+ * @param {Object} client - NostrClient instance
80
+ * @param {string} appname - Application namespace
81
+ * @param {string} holonId - Holon identifier
82
+ * @returns {Promise<string|null>} Public key or null if not found
83
+ */
84
+ export async function resolveHolonToPubkey(client, appname, holonId) {
85
+ // Direct pubkey
86
+ if (isPubkey(holonId)) {
87
+ return holonId;
88
+ }
89
+
90
+ // Registry lookup
91
+ const entry = await lookupHolon(client, appname, holonId);
92
+ return entry?.publicKey || null;
93
+ }
94
+
95
+ /**
96
+ * Unregister a holon
97
+ * @param {Object} client - NostrClient instance
98
+ * @param {string} appname - Application namespace
99
+ * @param {string} holonId - Holon identifier
100
+ * @returns {Promise<boolean>} Success indicator
101
+ */
102
+ export async function unregisterHolon(client, appname, holonId) {
103
+ // Can't unregister a direct pubkey
104
+ if (isPubkey(holonId)) {
105
+ return false;
106
+ }
107
+
108
+ // Mark as deleted by writing a tombstone
109
+ const entry = {
110
+ id: holonId,
111
+ holonId: holonId,
112
+ publicKey: null,
113
+ _deleted: true,
114
+ deletedAt: Date.now(),
115
+ deletedBy: client.publicKey,
116
+ };
117
+
118
+ return writeGlobal(client, appname, HOLON_REGISTRY_TABLE, entry);
119
+ }
120
+
121
+ /**
122
+ * Update a holon's alias or metadata
123
+ * @param {Object} client - NostrClient instance
124
+ * @param {string} appname - Application namespace
125
+ * @param {string} holonId - Holon identifier
126
+ * @param {Object} updates - Fields to update
127
+ * @param {string} [updates.alias] - New alias
128
+ * @returns {Promise<boolean>} Success indicator
129
+ */
130
+ export async function updateHolon(client, appname, holonId, updates = {}) {
131
+ const existing = await lookupHolon(client, appname, holonId);
132
+ if (!existing || existing.isDirect) {
133
+ return false;
134
+ }
135
+
136
+ const entry = {
137
+ ...existing,
138
+ ...updates,
139
+ updatedAt: Date.now(),
140
+ };
141
+
142
+ return writeGlobal(client, appname, HOLON_REGISTRY_TABLE, entry);
143
+ }
144
+
145
+ /**
146
+ * List all registered holons
147
+ * @param {Object} client - NostrClient instance
148
+ * @param {string} appname - Application namespace
149
+ * @returns {Promise<Object[]>} Array of registry entries
150
+ */
151
+ export async function listRegisteredHolons(client, appname) {
152
+ const entries = await getAllGlobal(client, appname, HOLON_REGISTRY_TABLE);
153
+ return (entries || []).filter(e => !e._deleted);
154
+ }
155
+
156
+ /**
157
+ * Find holons by public key
158
+ * @param {Object} client - NostrClient instance
159
+ * @param {string} appname - Application namespace
160
+ * @param {string} publicKey - Public key to search for
161
+ * @returns {Promise<Object[]>} Array of holons with this pubkey
162
+ */
163
+ export async function findHolonsByPubkey(client, appname, publicKey) {
164
+ const all = await listRegisteredHolons(client, appname);
165
+ return all.filter(e => e.publicKey === publicKey);
166
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @fileoverview Federation Module Index
3
+ *
4
+ * Exports all federation-related functionality in a modular structure.
5
+ * The federation system is now split into smaller, focused components:
6
+ *
7
+ * - capabilities: Token issuance and verification
8
+ * - registry: Partner and capability storage
9
+ * - handshake: NIP-44 encrypted DM protocol
10
+ * - discovery: Nostr event-based discovery
11
+ * - hologram: Reference/hologram management
12
+ * - request-card: Card-based configuration UI
13
+ * - card-storage: Persistent card state management
14
+ * - holon-registry: HolonId to pubKey mapping
15
+ *
16
+ * @module federation
17
+ */
18
+
19
+ // Core federation components
20
+ export * from './registry.js';
21
+ export * from './hologram.js';
22
+ export * from './discovery.js';
23
+
24
+ // Handshake protocol
25
+ export * from './handshake.js';
26
+
27
+ // Capability management
28
+ export * from './capabilities.js';
29
+
30
+ // Card-based configuration
31
+ export * from './request-card.js';
32
+ export * from './card-storage.js';
33
+
34
+ // Holon registry
35
+ export * from './holon-registry.js';
36
+
37
+ // Named exports for convenience
38
+ import * as registry from './registry.js';
39
+ import * as hologram from './hologram.js';
40
+ import * as discovery from './discovery.js';
41
+ import * as handshake from './handshake.js';
42
+ import * as capabilities from './capabilities.js';
43
+ import * as requestCard from './request-card.js';
44
+ import * as cardStorage from './card-storage.js';
45
+ import * as holonRegistry from './holon-registry.js';
46
+
47
+ export {
48
+ registry,
49
+ hologram,
50
+ discovery,
51
+ handshake,
52
+ capabilities,
53
+ requestCard,
54
+ cardStorage,
55
+ holonRegistry,
56
+ };
57
+
58
+ // Default export with all modules
59
+ export default {
60
+ registry,
61
+ hologram,
62
+ discovery,
63
+ handshake,
64
+ capabilities,
65
+ requestCard,
66
+ cardStorage,
67
+ holonRegistry,
68
+ };
@@ -1,6 +1,12 @@
1
1
  /**
2
- * Federation Registry - Manages cross-holosphere partnerships
3
- * Tracks federated partners and their capability tokens
2
+ * Federation Registry - UNIFIED MODEL
3
+ *
4
+ * Manages federation partnerships and capability tokens for both:
5
+ * - Self-federation (same author, different holons)
6
+ * - Cross-federation (different authors)
7
+ *
8
+ * In the unified model, all federation uses capabilities, including self-federation.
9
+ * This provides consistent security semantics across all federation types.
4
10
  */
5
11
 
6
12
  import { writeGlobal, readGlobal } from '../storage/global-tables.js';
@@ -384,3 +390,105 @@ export async function cleanupExpiredCapabilities(client, appname) {
384
390
 
385
391
  return { inboundRemoved, outboundRemoved };
386
392
  }
393
+
394
+ /**
395
+ * Store a self-capability (for same-author federation) - UNIFIED MODEL
396
+ *
397
+ * In the unified model, self-capabilities are stored similarly to cross-capabilities
398
+ * but marked as self-issued. This provides consistent capability management.
399
+ *
400
+ * @param {Object} client - NostrClient instance
401
+ * @param {string} appname - Application namespace
402
+ * @param {Object} capabilityInfo - Capability information
403
+ * @param {string} capabilityInfo.token - The capability token
404
+ * @param {Object} capabilityInfo.scope - Token scope
405
+ * @param {string[]} capabilityInfo.permissions - Granted permissions
406
+ * @returns {Promise<boolean>} Success indicator
407
+ */
408
+ export async function storeSelfCapability(client, appname, capabilityInfo) {
409
+ const registry = await getFederationRegistry(client, appname);
410
+
411
+ // Self-capabilities are stored under the user's own pubKey
412
+ const selfPubKey = client.publicKey;
413
+
414
+ // Find or create self-entry
415
+ let selfEntry = registry.federatedWith.find(p => p.pubKey === selfPubKey);
416
+
417
+ if (!selfEntry) {
418
+ selfEntry = {
419
+ pubKey: selfPubKey,
420
+ alias: 'self',
421
+ addedAt: Date.now(),
422
+ addedVia: 'self_capability',
423
+ isSelf: true,
424
+ inboundCapabilities: [],
425
+ outboundCapabilities: [],
426
+ selfCapabilities: [], // Special array for self-capabilities
427
+ };
428
+ registry.federatedWith.push(selfEntry);
429
+ }
430
+
431
+ if (!selfEntry.selfCapabilities) {
432
+ selfEntry.selfCapabilities = [];
433
+ }
434
+
435
+ // Check if we already have this capability (by scope match)
436
+ const existingIndex = selfEntry.selfCapabilities.findIndex(cap =>
437
+ JSON.stringify(cap.scope) === JSON.stringify(capabilityInfo.scope)
438
+ );
439
+
440
+ if (existingIndex >= 0) {
441
+ // Update existing capability
442
+ selfEntry.selfCapabilities[existingIndex] = {
443
+ ...capabilityInfo,
444
+ updatedAt: Date.now(),
445
+ isSelfCapability: true,
446
+ };
447
+ } else {
448
+ // Add new capability
449
+ selfEntry.selfCapabilities.push({
450
+ ...capabilityInfo,
451
+ issuedAt: Date.now(),
452
+ isSelfCapability: true,
453
+ });
454
+ }
455
+
456
+ return saveFederationRegistry(client, appname, registry);
457
+ }
458
+
459
+ /**
460
+ * Get self-capability for a scope - UNIFIED MODEL
461
+ *
462
+ * @param {Object} client - NostrClient instance
463
+ * @param {string} appname - Application namespace
464
+ * @param {Object} scope - Requested scope { holonId, lensName, dataId? }
465
+ * @returns {Promise<Object|null>} Self-capability or null
466
+ */
467
+ export async function getSelfCapability(client, appname, scope) {
468
+ const registry = await getFederationRegistry(client, appname);
469
+ const selfEntry = registry.federatedWith.find(p => p.pubKey === client.publicKey && p.isSelf);
470
+
471
+ if (!selfEntry || !selfEntry.selfCapabilities) {
472
+ return null;
473
+ }
474
+
475
+ // Find matching, non-expired self-capability
476
+ return selfEntry.selfCapabilities.find(cap => {
477
+ // Check expiration
478
+ if (cap.expires && cap.expires < Date.now()) {
479
+ return false;
480
+ }
481
+
482
+ // Check scope match (supports wildcards)
483
+ return matchScope(cap.scope, scope);
484
+ }) || null;
485
+ }
486
+
487
+ /**
488
+ * Check if a capability is a self-capability
489
+ * @param {Object} capabilityInfo - Capability info object
490
+ * @returns {boolean} True if self-capability
491
+ */
492
+ export function isSelfCapability(capabilityInfo) {
493
+ return capabilityInfo && capabilityInfo.isSelfCapability === true;
494
+ }