@gns-foundation/hive-worker 0.1.11 → 0.5.0

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.
@@ -0,0 +1,173 @@
1
+ // ============================================================
2
+ // Phase 4: Worker MobyDB Integration
3
+ // File: packages/hive-worker/src/mobydb_hooks.ts
4
+ //
5
+ // Hooks MobyDB into every compute operation.
6
+ // Call initWorkerMobyDB() at worker startup.
7
+ // ============================================================
8
+
9
+ import { initMobyDB, getMobyDB, currentEpoch, type MobyDB } from './mobydb';
10
+
11
+ let sealInterval: NodeJS.Timeout | null = null;
12
+ let syncInterval: NodeJS.Timeout | null = null;
13
+
14
+ // ─── Central API ────────────────────────────
15
+ const CENTRAL_URL = process.env.CENTRAL_API_URL || 'https://gns-browser-production.up.railway.app';
16
+
17
+ // ─── Initialize ─────────────────────────────
18
+
19
+ /**
20
+ * Initialize MobyDB for this worker.
21
+ * Call once at worker startup after identity is loaded.
22
+ */
23
+ export function initWorkerMobyDB(workerPk: string, h3Cell: string): MobyDB {
24
+ const db = initMobyDB(workerPk, h3Cell);
25
+
26
+ // Start auto-sealer (every 60 seconds)
27
+ if (!sealInterval) {
28
+ sealInterval = setInterval(() => {
29
+ const moby = getMobyDB();
30
+ if (!moby) return;
31
+ const seals = moby.autoSeal();
32
+ if (seals.length > 0) {
33
+ console.log(`🔒 Auto-sealed ${seals.length} epoch(s)`);
34
+ }
35
+ }, 60_000);
36
+ }
37
+
38
+ // Start sync to central (every 30 seconds)
39
+ if (!syncInterval) {
40
+ syncInterval = setInterval(() => {
41
+ syncToCentral().catch(err => {
42
+ console.error('⚠️ Sync to central failed:', err.message);
43
+ });
44
+ }, 30_000);
45
+ }
46
+
47
+ console.log(`🐋 Worker MobyDB ready (auto-seal: 60s, sync: 30s)`);
48
+ return db;
49
+ }
50
+
51
+ // ─── Compute Hooks ──────────────────────────
52
+
53
+ /**
54
+ * Hook: call after every inference.
55
+ * Writes an Inference record to local MobyDB.
56
+ */
57
+ export function afterInference(data: {
58
+ model: string;
59
+ provider: string;
60
+ tokens_in: number;
61
+ tokens_out: number;
62
+ latency_ms: number;
63
+ prompt_hash: string;
64
+ response_hash: string;
65
+ requester_pk: string;
66
+ job_id?: string;
67
+ }): string | null {
68
+ const moby = getMobyDB();
69
+ if (!moby) return null;
70
+
71
+ const record = moby.writeInference(data);
72
+ return record.record_hash;
73
+ }
74
+
75
+ /**
76
+ * Hook: call after every tile render/proxy.
77
+ * Writes a Tile record to local MobyDB.
78
+ */
79
+ export function afterTileRender(data: {
80
+ format: string;
81
+ zoom: number;
82
+ style: string;
83
+ tile_hash: string;
84
+ tile_bytes: number;
85
+ render_ms: number;
86
+ source: string;
87
+ cached: boolean;
88
+ parent_job?: string;
89
+ }): string | null {
90
+ const moby = getMobyDB();
91
+ if (!moby) return null;
92
+
93
+ const record = moby.writeTile(data);
94
+ return record.record_hash;
95
+ }
96
+
97
+ /**
98
+ * Hook: call after a compound job completes.
99
+ * Links all step records into one ComputeJob record.
100
+ */
101
+ export function afterComputeJob(data: {
102
+ job_id: string;
103
+ requester_pk: string;
104
+ steps: Array<{ id: string; type: string; record_hash: string }>;
105
+ total_gns: number;
106
+ stellar_tx?: string;
107
+ latency_ms: number;
108
+ }): string | null {
109
+ const moby = getMobyDB();
110
+ if (!moby) return null;
111
+
112
+ const record = moby.writeComputeJob(data);
113
+ return record.record_hash;
114
+ }
115
+
116
+ // ─── Sync to Central ────────────────────────
117
+
118
+ /**
119
+ * Push pending records to the central MobyDB server.
120
+ * Records are batched for efficiency.
121
+ */
122
+ async function syncToCentral(): Promise<void> {
123
+ const moby = getMobyDB();
124
+ if (!moby) return;
125
+
126
+ const pendingIds = moby.getPendingSync(20);
127
+ if (pendingIds.length === 0) return;
128
+
129
+ const records = pendingIds.map(id => moby.get(id)).filter(Boolean);
130
+ if (records.length === 0) return;
131
+
132
+ try {
133
+ const res = await fetch(`${CENTRAL_URL}/mobydb/sync`, {
134
+ method: 'POST',
135
+ headers: { 'Content-Type': 'application/json' },
136
+ body: JSON.stringify({ records }),
137
+ });
138
+
139
+ if (res.ok) {
140
+ moby.markSynced(pendingIds);
141
+ console.log(`📤 Synced ${records.length} records to central`);
142
+ }
143
+ } catch {
144
+ // Will retry next cycle
145
+ }
146
+ }
147
+
148
+ // ─── Status ─────────────────────────────────
149
+
150
+ export function getMobyDBStatus(): Record<string, any> | null {
151
+ const moby = getMobyDB();
152
+ if (!moby) return null;
153
+
154
+ return {
155
+ path: moby.path,
156
+ records: moby.recordCount,
157
+ stats: moby.stats(),
158
+ epoch: currentEpoch(),
159
+ };
160
+ }
161
+
162
+ // ─── Shutdown ───────────────────────────────
163
+
164
+ export function shutdownMobyDB(): void {
165
+ if (sealInterval) { clearInterval(sealInterval); sealInterval = null; }
166
+ if (syncInterval) { clearInterval(syncInterval); syncInterval = null; }
167
+ const moby = getMobyDB();
168
+ if (moby) {
169
+ // Final seal before shutdown
170
+ moby.autoSeal();
171
+ moby.close();
172
+ }
173
+ }