holosphere 1.1.20 ā 2.0.0-alpha1
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/.env.example +36 -0
- package/.eslintrc.json +16 -0
- package/.prettierrc.json +7 -0
- package/LICENSE +162 -38
- package/README.md +483 -367
- package/bin/holosphere-activitypub.js +158 -0
- package/cleanup-test-data.js +204 -0
- package/examples/demo.html +1333 -0
- package/examples/example-bot.js +197 -0
- package/package.json +47 -87
- package/scripts/check-bundle-size.js +54 -0
- package/scripts/check-quest-ids.js +77 -0
- package/scripts/import-holons.js +578 -0
- package/scripts/publish-to-relay.js +101 -0
- package/scripts/read-example.js +186 -0
- package/scripts/relay-diagnostic.js +59 -0
- package/scripts/relay-example.js +179 -0
- package/scripts/resync-to-relay.js +245 -0
- package/scripts/revert-import.js +196 -0
- package/scripts/test-hybrid-mode.js +108 -0
- package/scripts/test-local-storage.js +63 -0
- package/scripts/test-nostr-direct.js +55 -0
- package/scripts/test-read-data.js +45 -0
- package/scripts/test-write-read.js +63 -0
- package/scripts/verify-import.js +95 -0
- package/scripts/verify-relay-data.js +139 -0
- package/src/ai/aggregation.js +319 -0
- package/src/ai/breakdown.js +511 -0
- package/src/ai/classifier.js +217 -0
- package/src/ai/council.js +228 -0
- package/src/ai/embeddings.js +279 -0
- package/src/ai/federation-ai.js +324 -0
- package/src/ai/h3-ai.js +955 -0
- package/src/ai/index.js +112 -0
- package/src/ai/json-ops.js +225 -0
- package/src/ai/llm-service.js +205 -0
- package/src/ai/nl-query.js +223 -0
- package/src/ai/relationships.js +353 -0
- package/src/ai/schema-extractor.js +218 -0
- package/src/ai/spatial.js +293 -0
- package/src/ai/tts.js +194 -0
- package/src/content/social-protocols.js +168 -0
- package/src/core/holosphere.js +273 -0
- package/src/crypto/secp256k1.js +259 -0
- package/src/federation/discovery.js +334 -0
- package/src/federation/hologram.js +1042 -0
- package/src/federation/registry.js +386 -0
- package/src/hierarchical/upcast.js +110 -0
- package/src/index.js +2669 -0
- package/src/schema/validator.js +91 -0
- package/src/spatial/h3-operations.js +110 -0
- package/src/storage/backend-factory.js +125 -0
- package/src/storage/backend-interface.js +142 -0
- package/src/storage/backends/activitypub/server.js +653 -0
- package/src/storage/backends/activitypub-backend.js +272 -0
- package/src/storage/backends/gundb-backend.js +233 -0
- package/src/storage/backends/nostr-backend.js +136 -0
- package/src/storage/filesystem-storage-browser.js +41 -0
- package/src/storage/filesystem-storage.js +138 -0
- package/src/storage/global-tables.js +81 -0
- package/src/storage/gun-async.js +281 -0
- package/src/storage/gun-wrapper.js +221 -0
- package/src/storage/indexeddb-storage.js +122 -0
- package/src/storage/key-storage-simple.js +76 -0
- package/src/storage/key-storage.js +136 -0
- package/src/storage/memory-storage.js +59 -0
- package/src/storage/migration.js +338 -0
- package/src/storage/nostr-async.js +811 -0
- package/src/storage/nostr-client.js +939 -0
- package/src/storage/nostr-wrapper.js +211 -0
- package/src/storage/outbox-queue.js +208 -0
- package/src/storage/persistent-storage.js +109 -0
- package/src/storage/sync-service.js +164 -0
- package/src/subscriptions/manager.js +142 -0
- package/test-ai-real-api.js +202 -0
- package/tests/unit/ai/aggregation.test.js +295 -0
- package/tests/unit/ai/breakdown.test.js +446 -0
- package/tests/unit/ai/classifier.test.js +294 -0
- package/tests/unit/ai/council.test.js +262 -0
- package/tests/unit/ai/embeddings.test.js +384 -0
- package/tests/unit/ai/federation-ai.test.js +344 -0
- package/tests/unit/ai/h3-ai.test.js +458 -0
- package/tests/unit/ai/index.test.js +304 -0
- package/tests/unit/ai/json-ops.test.js +307 -0
- package/tests/unit/ai/llm-service.test.js +390 -0
- package/tests/unit/ai/nl-query.test.js +383 -0
- package/tests/unit/ai/relationships.test.js +311 -0
- package/tests/unit/ai/schema-extractor.test.js +384 -0
- package/tests/unit/ai/spatial.test.js +279 -0
- package/tests/unit/ai/tts.test.js +279 -0
- package/tests/unit/content.test.js +332 -0
- package/tests/unit/contract/core.test.js +88 -0
- package/tests/unit/contract/crypto.test.js +198 -0
- package/tests/unit/contract/data.test.js +223 -0
- package/tests/unit/contract/federation.test.js +181 -0
- package/tests/unit/contract/hierarchical.test.js +113 -0
- package/tests/unit/contract/schema.test.js +114 -0
- package/tests/unit/contract/social.test.js +217 -0
- package/tests/unit/contract/spatial.test.js +110 -0
- package/tests/unit/contract/subscriptions.test.js +128 -0
- package/tests/unit/contract/utils.test.js +159 -0
- package/tests/unit/core.test.js +152 -0
- package/tests/unit/crypto.test.js +328 -0
- package/tests/unit/federation.test.js +234 -0
- package/tests/unit/gun-async.test.js +252 -0
- package/tests/unit/hierarchical.test.js +399 -0
- package/tests/unit/integration/scenario-01-geographic-storage.test.js +74 -0
- package/tests/unit/integration/scenario-02-federation.test.js +76 -0
- package/tests/unit/integration/scenario-03-subscriptions.test.js +102 -0
- package/tests/unit/integration/scenario-04-validation.test.js +129 -0
- package/tests/unit/integration/scenario-05-hierarchy.test.js +125 -0
- package/tests/unit/integration/scenario-06-social.test.js +135 -0
- package/tests/unit/integration/scenario-07-persistence.test.js +130 -0
- package/tests/unit/integration/scenario-08-authorization.test.js +161 -0
- package/tests/unit/integration/scenario-09-cross-dimensional.test.js +139 -0
- package/tests/unit/integration/scenario-10-cross-holosphere-capabilities.test.js +357 -0
- package/tests/unit/integration/scenario-11-cross-holosphere-federation.test.js +410 -0
- package/tests/unit/integration/scenario-12-capability-federated-read.test.js +719 -0
- package/tests/unit/performance/benchmark.test.js +85 -0
- package/tests/unit/schema.test.js +213 -0
- package/tests/unit/spatial.test.js +158 -0
- package/tests/unit/storage.test.js +195 -0
- package/tests/unit/subscriptions.test.js +328 -0
- package/tests/unit/test-data-permanence-debug.js +197 -0
- package/tests/unit/test-data-permanence.js +340 -0
- package/tests/unit/test-key-persistence-fixed.js +148 -0
- package/tests/unit/test-key-persistence.js +172 -0
- package/tests/unit/test-relay-permanence.js +376 -0
- package/tests/unit/test-second-node.js +95 -0
- package/tests/unit/test-simple-write.js +89 -0
- package/vite.config.js +49 -0
- package/vitest.config.js +20 -0
- package/FEDERATION.md +0 -213
- package/compute.js +0 -298
- package/content.js +0 -980
- package/federation.js +0 -1234
- package/global.js +0 -736
- package/hexlib.js +0 -335
- package/hologram.js +0 -183
- package/holosphere-bundle.esm.js +0 -33256
- package/holosphere-bundle.js +0 -33287
- package/holosphere-bundle.min.js +0 -39
- package/holosphere.d.ts +0 -601
- package/holosphere.js +0 -719
- package/node.js +0 -246
- package/schema.js +0 -139
- package/utils.js +0 -302
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example Quest Bot with Network Synchronization
|
|
3
|
+
*
|
|
4
|
+
* This example shows how to create a bot that manages quests
|
|
5
|
+
* with proper Nostr relay synchronization across multiple nodes.
|
|
6
|
+
*
|
|
7
|
+
* Configuration via environment variables (see .env.example):
|
|
8
|
+
* - HOLOSPHERE_RELAYS: Comma-separated relay URLs
|
|
9
|
+
* - HOLOSPHERE_PRIVATE_KEY: Hex private key for persistent identity
|
|
10
|
+
* - HOLOSPHERE_APP_NAME: Application namespace
|
|
11
|
+
* - OPENAI_API_KEY: Enable AI features (optional)
|
|
12
|
+
*
|
|
13
|
+
* Or pass directly in the config object.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { HoloSphere } from '../dist/esm/holosphere.js';
|
|
17
|
+
|
|
18
|
+
// Relay configuration - use env vars or these defaults
|
|
19
|
+
const RELAYS = process.env.HOLOSPHERE_RELAYS?.split(',') || [
|
|
20
|
+
'wss://relay.holons.io',
|
|
21
|
+
'wss://relay.nostr.band',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
// Initialize HoloSphere with real relays for network synchronization
|
|
25
|
+
// Private key is read from HOLOSPHERE_PRIVATE_KEY env var automatically
|
|
26
|
+
// AI features enabled if OPENAI_API_KEY env var is set
|
|
27
|
+
const hs = new HoloSphere({
|
|
28
|
+
appName: process.env.HOLOSPHERE_APP_NAME || 'quest-game',
|
|
29
|
+
relays: RELAYS,
|
|
30
|
+
logLevel: 'INFO',
|
|
31
|
+
// privateKey: process.env.HOLOSPHERE_PRIVATE_KEY, // Auto-read from env
|
|
32
|
+
// openaiKey: process.env.OPENAI_API_KEY, // Auto-read from env
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
console.log('Quest Bot initialized with relays:', hs.config.relays);
|
|
36
|
+
console.log('Bot Public Key:', hs.client.publicKey);
|
|
37
|
+
|
|
38
|
+
// Use a global holon for quest storage (not location-specific)
|
|
39
|
+
const QUEST_HOLON = 'global://quests';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create a new quest
|
|
43
|
+
*/
|
|
44
|
+
async function createQuest(questData) {
|
|
45
|
+
console.log('\nš Creating quest:', questData.title);
|
|
46
|
+
|
|
47
|
+
const result = await hs.write(QUEST_HOLON, 'quests', questData);
|
|
48
|
+
|
|
49
|
+
if (result) {
|
|
50
|
+
console.log('ā
Quest created successfully:', questData.id || questData.title);
|
|
51
|
+
console.log(' This quest is now published to Nostr relays and will sync across all nodes!');
|
|
52
|
+
} else {
|
|
53
|
+
console.error('ā Failed to create quest');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* List all available quests
|
|
61
|
+
*/
|
|
62
|
+
async function listQuests() {
|
|
63
|
+
console.log('\nš Fetching all quests...');
|
|
64
|
+
|
|
65
|
+
const quests = await hs.read(QUEST_HOLON, 'quests');
|
|
66
|
+
|
|
67
|
+
if (quests && quests.length > 0) {
|
|
68
|
+
console.log(`\nFound ${quests.length} quest(s):\n`);
|
|
69
|
+
quests.forEach((quest, index) => {
|
|
70
|
+
console.log(`${index + 1}. ${quest.title}`);
|
|
71
|
+
console.log(` ID: ${quest.id}`);
|
|
72
|
+
console.log(` Status: ${quest.status || 'active'}`);
|
|
73
|
+
console.log(` Description: ${quest.description || 'No description'}`);
|
|
74
|
+
console.log('');
|
|
75
|
+
});
|
|
76
|
+
} else {
|
|
77
|
+
console.log('No quests found.');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return quests;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Update a quest
|
|
85
|
+
*/
|
|
86
|
+
async function updateQuest(questId, updates) {
|
|
87
|
+
console.log(`\nāļø Updating quest: ${questId}`);
|
|
88
|
+
|
|
89
|
+
const quests = await hs.read(QUEST_HOLON, 'quests');
|
|
90
|
+
const quest = quests.find(q => q.id === questId);
|
|
91
|
+
|
|
92
|
+
if (!quest) {
|
|
93
|
+
console.error('ā Quest not found');
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const updatedQuest = { ...quest, ...updates };
|
|
98
|
+
const result = await hs.write(QUEST_HOLON, 'quests', updatedQuest);
|
|
99
|
+
|
|
100
|
+
if (result) {
|
|
101
|
+
console.log('ā
Quest updated successfully');
|
|
102
|
+
} else {
|
|
103
|
+
console.error('ā Failed to update quest');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Delete a quest
|
|
111
|
+
*/
|
|
112
|
+
async function deleteQuest(questId) {
|
|
113
|
+
console.log(`\nšļø Deleting quest: ${questId}`);
|
|
114
|
+
|
|
115
|
+
// Read current quests
|
|
116
|
+
const quests = await hs.read(QUEST_HOLON, 'quests');
|
|
117
|
+
const filtered = quests.filter(q => q.id !== questId);
|
|
118
|
+
|
|
119
|
+
if (filtered.length === quests.length) {
|
|
120
|
+
console.error('ā Quest not found');
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Write back without the deleted quest
|
|
125
|
+
// (In a production system, you'd handle this differently)
|
|
126
|
+
console.log('ā ļø Note: Deletion in Nostr is done by marking as deleted, not removing');
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Subscribe to quest changes in real-time
|
|
132
|
+
*/
|
|
133
|
+
function subscribeToQuests(callback) {
|
|
134
|
+
console.log('\nš Subscribing to quest changes...');
|
|
135
|
+
|
|
136
|
+
const subscription = hs.subscribe(QUEST_HOLON, 'quests', (quest) => {
|
|
137
|
+
console.log('\nš New quest event received:', quest.title || quest.id);
|
|
138
|
+
if (callback) callback(quest);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
console.log('ā
Subscribed to quest updates');
|
|
142
|
+
return subscription;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Example usage
|
|
146
|
+
async function main() {
|
|
147
|
+
console.log('\n=== Quest Bot Demo ===\n');
|
|
148
|
+
|
|
149
|
+
// Wait a moment for relays to connect
|
|
150
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
151
|
+
|
|
152
|
+
// Create some example quests
|
|
153
|
+
await createQuest({
|
|
154
|
+
id: `quest-${Date.now()}-1`,
|
|
155
|
+
title: 'Gather Ancient Scrolls',
|
|
156
|
+
description: 'Find 5 ancient scrolls hidden in the forest',
|
|
157
|
+
reward: 1000,
|
|
158
|
+
difficulty: 'medium'
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await createQuest({
|
|
162
|
+
id: `quest-${Date.now()}-2`,
|
|
163
|
+
title: 'Defeat the Dragon',
|
|
164
|
+
description: 'Slay the dragon terrorizing the village',
|
|
165
|
+
reward: 5000,
|
|
166
|
+
difficulty: 'hard'
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Wait for data to sync
|
|
170
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
171
|
+
|
|
172
|
+
// List all quests
|
|
173
|
+
await listQuests();
|
|
174
|
+
|
|
175
|
+
console.log('\n=== Bot is now running ===');
|
|
176
|
+
console.log('Quests will sync to other nodes using these relays:');
|
|
177
|
+
hs.config.relays.forEach(relay => console.log(' -', relay));
|
|
178
|
+
console.log('\nPress Ctrl+C to exit');
|
|
179
|
+
|
|
180
|
+
// Subscribe to changes
|
|
181
|
+
subscribeToQuests((quest) => {
|
|
182
|
+
console.log('Real-time update received for quest:', quest.title);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Run the bot
|
|
187
|
+
main().catch(console.error);
|
|
188
|
+
|
|
189
|
+
// Export functions for use in other scripts
|
|
190
|
+
export {
|
|
191
|
+
createQuest,
|
|
192
|
+
listQuests,
|
|
193
|
+
updateQuest,
|
|
194
|
+
deleteQuest,
|
|
195
|
+
subscribeToQuests,
|
|
196
|
+
hs
|
|
197
|
+
};
|
package/package.json
CHANGED
|
@@ -1,104 +1,64 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "holosphere",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Holonic
|
|
5
|
-
"main": "holosphere.js",
|
|
6
|
-
"module": "holosphere.js",
|
|
7
|
-
"types": "holosphere.d.ts",
|
|
3
|
+
"version": "2.0.0-alpha1",
|
|
4
|
+
"description": "Holonic geospatial communication infrastructure combining H3 hexagonal indexing with GunDB distributed P2P storage",
|
|
8
5
|
"type": "module",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"build": "npm run build:browser",
|
|
12
|
-
"prepare": "npm run build",
|
|
13
|
-
"build:browser": "node build.js",
|
|
14
|
-
"build:bundle": "node build.js",
|
|
15
|
-
"prepublishOnly": "npm run build",
|
|
16
|
-
"publish:cdn": "npm publish && echo 'Package published to npm and will be available on CDNs within minutes'",
|
|
17
|
-
"publish:force": "npm publish --force && echo 'Package force published to npm and will be available on CDNs within minutes'",
|
|
18
|
-
"prepublish:skip-tests": "npm run build"
|
|
19
|
-
},
|
|
20
|
-
"author": "Roberto Valenti",
|
|
21
|
-
"license": "GPL-3.0-or-later",
|
|
22
|
-
"dependencies": {
|
|
23
|
-
"ajv": "^8.12.0",
|
|
24
|
-
"gun": "^0.2020.1240",
|
|
25
|
-
"h3-js": "^4.1.0",
|
|
26
|
-
"openai": "^4.85.1"
|
|
6
|
+
"bin": {
|
|
7
|
+
"holosphere-activitypub": "./bin/holosphere-activitypub.js"
|
|
27
8
|
},
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
"jest": {
|
|
34
|
-
"testEnvironment": "node",
|
|
35
|
-
"transform": {}
|
|
36
|
-
},
|
|
37
|
-
"browser": "holosphere.js",
|
|
38
|
-
"unpkg": "holosphere-bundle.js",
|
|
39
|
-
"jsdelivr": "holosphere-bundle.js",
|
|
40
|
-
"cdn": "holosphere-bundle.js",
|
|
41
|
-
"files": [
|
|
42
|
-
"holosphere.js",
|
|
43
|
-
"holosphere-bundle.js",
|
|
44
|
-
"holosphere-bundle.min.js",
|
|
45
|
-
"holosphere-bundle.esm.js",
|
|
46
|
-
"holosphere.d.ts",
|
|
47
|
-
"federation.js",
|
|
48
|
-
"schema.js",
|
|
49
|
-
"content.js",
|
|
50
|
-
"node.js",
|
|
51
|
-
"global.js",
|
|
52
|
-
"hologram.js",
|
|
53
|
-
"compute.js",
|
|
54
|
-
"utils.js",
|
|
55
|
-
"hexlib.js",
|
|
56
|
-
"README.md",
|
|
57
|
-
"LICENSE",
|
|
58
|
-
"FEDERATION.md"
|
|
59
|
-
],
|
|
9
|
+
"main": "./dist/cjs/holosphere.cjs",
|
|
10
|
+
"module": "./dist/esm/holosphere.js",
|
|
11
|
+
"browser": "./dist/cdn/holosphere.min.js",
|
|
12
|
+
"types": "./dist/types/index.d.ts",
|
|
60
13
|
"exports": {
|
|
61
14
|
".": {
|
|
62
|
-
"import": "./holosphere.js",
|
|
63
|
-
"require": "./holosphere.
|
|
64
|
-
|
|
65
|
-
},
|
|
66
|
-
"./bundle": "./holosphere-bundle.js",
|
|
67
|
-
"./bundle/esm": "./holosphere-bundle.esm.js",
|
|
68
|
-
"./bundle/min": "./holosphere-bundle.min.js",
|
|
69
|
-
"./browser": "./holosphere-bundle.js",
|
|
70
|
-
"./node": "./holosphere.js"
|
|
15
|
+
"import": "./dist/esm/holosphere.js",
|
|
16
|
+
"require": "./dist/cjs/holosphere.cjs"
|
|
17
|
+
}
|
|
71
18
|
},
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "vite",
|
|
21
|
+
"build": "vite build",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"lint": "eslint src tests",
|
|
26
|
+
"format": "prettier --write \"src/**/*.js\" \"tests/**/*.js\""
|
|
75
27
|
},
|
|
76
28
|
"keywords": [
|
|
77
|
-
"holonic",
|
|
78
29
|
"geospatial",
|
|
79
30
|
"h3",
|
|
80
|
-
"
|
|
31
|
+
"gundb",
|
|
81
32
|
"p2p",
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"cdn",
|
|
87
|
-
"browser",
|
|
88
|
-
"realtime",
|
|
89
|
-
"webrtc"
|
|
33
|
+
"distributed",
|
|
34
|
+
"holonic",
|
|
35
|
+
"federation",
|
|
36
|
+
"noosphere"
|
|
90
37
|
],
|
|
91
|
-
"
|
|
92
|
-
|
|
38
|
+
"author": "",
|
|
39
|
+
"license": "MIT",
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@noble/curves": "^1.3.0",
|
|
42
|
+
"ajv": "^8.12.0",
|
|
43
|
+
"dotenv": "^17.2.3",
|
|
44
|
+
"express": "^4.21.0",
|
|
45
|
+
"h3-js": "^4.1.0",
|
|
46
|
+
"nostr-tools": "^2.17.0",
|
|
47
|
+
"openai": "^4.85.1",
|
|
48
|
+
"ws": "^8.18.3"
|
|
93
49
|
},
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
"gun": "^0.2020.1240",
|
|
97
|
-
"h3-js": "^4.1.0"
|
|
50
|
+
"optionalDependencies": {
|
|
51
|
+
"gun": "^0.2020.1241"
|
|
98
52
|
},
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
|
|
102
|
-
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@vitest/coverage-v8": "^1.3.0",
|
|
55
|
+
"eslint": "^8.57.0",
|
|
56
|
+
"prettier": "^3.2.5",
|
|
57
|
+
"terser": "^5.44.0",
|
|
58
|
+
"vite": "^5.1.0",
|
|
59
|
+
"vitest": "^1.3.0"
|
|
60
|
+
},
|
|
61
|
+
"engines": {
|
|
62
|
+
"node": ">=18.0.0"
|
|
103
63
|
}
|
|
104
64
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Bundle Size Validation Script
|
|
5
|
+
* Checks that CDN bundle is < 1MB minified+gzipped
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import { gzipSync } from 'zlib';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import { dirname, join } from 'path';
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
|
|
16
|
+
const MAX_SIZE_MB = 1;
|
|
17
|
+
const MAX_SIZE_BYTES = MAX_SIZE_MB * 1024 * 1024;
|
|
18
|
+
|
|
19
|
+
const bundlePath = join(__dirname, '../dist/cdn/holosphere.min.js');
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
// Read bundle
|
|
23
|
+
const bundleContent = fs.readFileSync(bundlePath);
|
|
24
|
+
const uncompressedSize = bundleContent.length;
|
|
25
|
+
|
|
26
|
+
// Gzip
|
|
27
|
+
const gzipped = gzipSync(bundleContent, { level: 9 });
|
|
28
|
+
const gzippedSize = gzipped.length;
|
|
29
|
+
|
|
30
|
+
// Calculate sizes in MB
|
|
31
|
+
const uncompressedMB = (uncompressedSize / 1024 / 1024).toFixed(2);
|
|
32
|
+
const gzippedMB = (gzippedSize / 1024 / 1024).toFixed(2);
|
|
33
|
+
|
|
34
|
+
console.log(`\nš¦ Bundle Size Report`);
|
|
35
|
+
console.log(`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
36
|
+
console.log(`File: dist/cdn/holosphere.min.js`);
|
|
37
|
+
console.log(`Uncompressed: ${uncompressedMB} MB (${uncompressedSize.toLocaleString()} bytes)`);
|
|
38
|
+
console.log(`Gzipped: ${gzippedMB} MB (${gzippedSize.toLocaleString()} bytes)`);
|
|
39
|
+
console.log(`Target: <${MAX_SIZE_MB} MB (${MAX_SIZE_BYTES.toLocaleString()} bytes)`);
|
|
40
|
+
console.log(`āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā`);
|
|
41
|
+
|
|
42
|
+
if (gzippedSize > MAX_SIZE_BYTES) {
|
|
43
|
+
console.error(`\nā FAIL: Bundle size ${gzippedMB} MB exceeds ${MAX_SIZE_MB} MB limit`);
|
|
44
|
+
console.error(` Reduce by ${(gzippedSize - MAX_SIZE_BYTES)} bytes\n`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
} else {
|
|
47
|
+
const remainingMB = ((MAX_SIZE_BYTES - gzippedSize) / 1024 / 1024).toFixed(2);
|
|
48
|
+
console.log(`\nā
PASS: Bundle size OK (${remainingMB} MB headroom)\n`);
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(`\nā ERROR: ${error.message}\n`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Check what quest IDs are actually stored
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { HoloSphere } from '../src/index.js';
|
|
8
|
+
import dotenv from 'dotenv';
|
|
9
|
+
|
|
10
|
+
dotenv.config();
|
|
11
|
+
|
|
12
|
+
async function main() {
|
|
13
|
+
console.log('Checking Quest IDs in Storage');
|
|
14
|
+
console.log('==============================\n');
|
|
15
|
+
|
|
16
|
+
const holonId = '235114395';
|
|
17
|
+
|
|
18
|
+
const hs = new HoloSphere({
|
|
19
|
+
appName: 'Holons',
|
|
20
|
+
relays: [],
|
|
21
|
+
persistence: true,
|
|
22
|
+
logLevel: 'ERROR',
|
|
23
|
+
privateKey: process.env.HOLOSPHERE_PRIVATE_KEY
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
27
|
+
|
|
28
|
+
const quests = await hs.read(holonId, 'quests');
|
|
29
|
+
|
|
30
|
+
if (!quests) {
|
|
31
|
+
console.log('No quests found!');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const questIds = Object.keys(quests);
|
|
36
|
+
console.log(`Total quests: ${questIds.length}\n`);
|
|
37
|
+
|
|
38
|
+
// Show first 30 quests with their original IDs
|
|
39
|
+
console.log('Quest IDs and their original IDs:\n');
|
|
40
|
+
console.log('Stored ID'.padEnd(15) + 'Original ID'.padEnd(15) + 'Title');
|
|
41
|
+
console.log('-'.repeat(80));
|
|
42
|
+
|
|
43
|
+
questIds.slice(0, 30).forEach(id => {
|
|
44
|
+
const quest = quests[id];
|
|
45
|
+
const origId = quest.id || 'N/A';
|
|
46
|
+
const title = (quest.title || 'N/A').substring(0, 40);
|
|
47
|
+
console.log(id.toString().padEnd(15) + origId.toString().padEnd(15) + title);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Check if specific quest IDs exist in the original id field
|
|
51
|
+
console.log('\n' + '='.repeat(80));
|
|
52
|
+
console.log('Searching for original quest IDs 1002, 10026, 1073, 1005, 1011:\n');
|
|
53
|
+
|
|
54
|
+
const targetIds = ['1002', '10026', '1073', '1005', '1011'];
|
|
55
|
+
for (const targetId of targetIds) {
|
|
56
|
+
const found = questIds.find(key => {
|
|
57
|
+
const quest = quests[key];
|
|
58
|
+
return quest.id && quest.id.toString() === targetId;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (found) {
|
|
62
|
+
const quest = quests[found];
|
|
63
|
+
console.log(`ā Quest ${targetId} found at key "${found}"`);
|
|
64
|
+
console.log(` Title: ${quest.title || 'N/A'}`);
|
|
65
|
+
console.log(` Status: ${quest.status || 'N/A'}\n`);
|
|
66
|
+
} else {
|
|
67
|
+
console.log(`ā Quest ${targetId} not found\n`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
main().catch(error => {
|
|
75
|
+
console.error('Error:', error);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|