@bcts/hubert 1.0.0-alpha.17
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/LICENSE +48 -0
- package/README.md +18 -0
- package/dist/arid-derivation-1CJuU-kZ.cjs +150 -0
- package/dist/arid-derivation-1CJuU-kZ.cjs.map +1 -0
- package/dist/arid-derivation-CbqACjdg.mjs +126 -0
- package/dist/arid-derivation-CbqACjdg.mjs.map +1 -0
- package/dist/bin/hubert.cjs +384 -0
- package/dist/bin/hubert.cjs.map +1 -0
- package/dist/bin/hubert.d.cts +1 -0
- package/dist/bin/hubert.d.mts +1 -0
- package/dist/bin/hubert.mjs +383 -0
- package/dist/bin/hubert.mjs.map +1 -0
- package/dist/chunk-CbDLau6x.cjs +34 -0
- package/dist/hybrid/index.cjs +14 -0
- package/dist/hybrid/index.d.cts +3 -0
- package/dist/hybrid/index.d.mts +3 -0
- package/dist/hybrid/index.mjs +6 -0
- package/dist/hybrid-BZhumygj.mjs +356 -0
- package/dist/hybrid-BZhumygj.mjs.map +1 -0
- package/dist/hybrid-dX5JLumO.cjs +410 -0
- package/dist/hybrid-dX5JLumO.cjs.map +1 -0
- package/dist/index-BEzpUC7r.d.mts +380 -0
- package/dist/index-BEzpUC7r.d.mts.map +1 -0
- package/dist/index-C2F6ugLL.d.mts +210 -0
- package/dist/index-C2F6ugLL.d.mts.map +1 -0
- package/dist/index-CUnDouMb.d.mts +215 -0
- package/dist/index-CUnDouMb.d.mts.map +1 -0
- package/dist/index-CV6lZJqY.d.cts +380 -0
- package/dist/index-CV6lZJqY.d.cts.map +1 -0
- package/dist/index-CY3TCzIm.d.cts +217 -0
- package/dist/index-CY3TCzIm.d.cts.map +1 -0
- package/dist/index-DEr4SR1J.d.cts +215 -0
- package/dist/index-DEr4SR1J.d.cts.map +1 -0
- package/dist/index-T1LHanIb.d.mts +217 -0
- package/dist/index-T1LHanIb.d.mts.map +1 -0
- package/dist/index-jyzuOhFB.d.cts +210 -0
- package/dist/index-jyzuOhFB.d.cts.map +1 -0
- package/dist/index.cjs +60 -0
- package/dist/index.d.cts +161 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +161 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +10 -0
- package/dist/ipfs/index.cjs +13 -0
- package/dist/ipfs/index.d.cts +3 -0
- package/dist/ipfs/index.d.mts +3 -0
- package/dist/ipfs/index.mjs +5 -0
- package/dist/ipfs-BRMMCBjv.mjs +1 -0
- package/dist/ipfs-CetOVQcO.cjs +0 -0
- package/dist/kv-BAmhmMOo.cjs +425 -0
- package/dist/kv-BAmhmMOo.cjs.map +1 -0
- package/dist/kv-C-emxv0w.mjs +375 -0
- package/dist/kv-C-emxv0w.mjs.map +1 -0
- package/dist/kv-DJiKvypY.mjs +403 -0
- package/dist/kv-DJiKvypY.mjs.map +1 -0
- package/dist/kv-store-DmngWWuw.d.mts +183 -0
- package/dist/kv-store-DmngWWuw.d.mts.map +1 -0
- package/dist/kv-store-ww-AUyLd.d.cts +183 -0
- package/dist/kv-store-ww-AUyLd.d.cts.map +1 -0
- package/dist/kv-yjvQa_LH.cjs +457 -0
- package/dist/kv-yjvQa_LH.cjs.map +1 -0
- package/dist/logging-hmzNzifq.mjs +158 -0
- package/dist/logging-hmzNzifq.mjs.map +1 -0
- package/dist/logging-qc9uMgil.cjs +212 -0
- package/dist/logging-qc9uMgil.cjs.map +1 -0
- package/dist/mainline/index.cjs +12 -0
- package/dist/mainline/index.d.cts +3 -0
- package/dist/mainline/index.d.mts +3 -0
- package/dist/mainline/index.mjs +5 -0
- package/dist/mainline-D_jfeFMh.cjs +0 -0
- package/dist/mainline-cFIuXbo-.mjs +1 -0
- package/dist/server/index.cjs +14 -0
- package/dist/server/index.d.cts +3 -0
- package/dist/server/index.d.mts +3 -0
- package/dist/server/index.mjs +3 -0
- package/dist/server-BBNRZ30D.cjs +912 -0
- package/dist/server-BBNRZ30D.cjs.map +1 -0
- package/dist/server-DVyk9gqU.mjs +836 -0
- package/dist/server-DVyk9gqU.mjs.map +1 -0
- package/package.json +125 -0
- package/src/arid-derivation.ts +155 -0
- package/src/bin/hubert.ts +667 -0
- package/src/error.ts +89 -0
- package/src/hybrid/error.ts +77 -0
- package/src/hybrid/index.ts +24 -0
- package/src/hybrid/kv.ts +236 -0
- package/src/hybrid/reference.ts +176 -0
- package/src/index.ts +145 -0
- package/src/ipfs/error.ts +83 -0
- package/src/ipfs/index.ts +24 -0
- package/src/ipfs/kv.ts +476 -0
- package/src/ipfs/value.ts +85 -0
- package/src/kv-store.ts +128 -0
- package/src/logging.ts +88 -0
- package/src/mainline/error.ts +108 -0
- package/src/mainline/index.ts +23 -0
- package/src/mainline/kv.ts +411 -0
- package/src/server/error.ts +83 -0
- package/src/server/index.ts +29 -0
- package/src/server/kv.ts +211 -0
- package/src/server/memory-kv.ts +191 -0
- package/src/server/server-kv.ts +92 -0
- package/src/server/server.ts +369 -0
- package/src/server/sqlite-kv.ts +295 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-CbDLau6x.cjs');
|
|
2
|
+
const require_logging = require('./logging-qc9uMgil.cjs');
|
|
3
|
+
const require_kv = require('./kv-yjvQa_LH.cjs');
|
|
4
|
+
const require_kv$1 = require('./kv-BAmhmMOo.cjs');
|
|
5
|
+
let _bcts_components = require("@bcts/components");
|
|
6
|
+
let _bcts_envelope = require("@bcts/envelope");
|
|
7
|
+
let _bcts_known_values = require("@bcts/known-values");
|
|
8
|
+
|
|
9
|
+
//#region src/hybrid/error.ts
|
|
10
|
+
/**
|
|
11
|
+
* Hybrid-specific errors.
|
|
12
|
+
*
|
|
13
|
+
* Port of hybrid/error.rs from hubert-rust.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Base class for Hybrid-specific errors.
|
|
19
|
+
*
|
|
20
|
+
* @category Hybrid
|
|
21
|
+
*/
|
|
22
|
+
var HybridError = class extends require_logging.HubertError {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "HybridError";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Referenced IPFS content not found.
|
|
30
|
+
*
|
|
31
|
+
* Port of `Error::ContentNotFound` from hybrid/error.rs line 4-5.
|
|
32
|
+
*
|
|
33
|
+
* @category Hybrid
|
|
34
|
+
*/
|
|
35
|
+
var ContentNotFoundError = class extends HybridError {
|
|
36
|
+
constructor() {
|
|
37
|
+
super("Referenced IPFS content not found");
|
|
38
|
+
this.name = "ContentNotFoundError";
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Not a reference envelope.
|
|
43
|
+
*
|
|
44
|
+
* Port of `Error::NotReferenceEnvelope` from hybrid/error.rs line 7-8.
|
|
45
|
+
*
|
|
46
|
+
* @category Hybrid
|
|
47
|
+
*/
|
|
48
|
+
var NotReferenceEnvelopeError = class extends HybridError {
|
|
49
|
+
constructor() {
|
|
50
|
+
super("Not a reference envelope");
|
|
51
|
+
this.name = "NotReferenceEnvelopeError";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Invalid ARID in reference envelope.
|
|
56
|
+
*
|
|
57
|
+
* Port of `Error::InvalidReferenceArid` from hybrid/error.rs line 10-11.
|
|
58
|
+
*
|
|
59
|
+
* @category Hybrid
|
|
60
|
+
*/
|
|
61
|
+
var InvalidReferenceAridError = class extends HybridError {
|
|
62
|
+
constructor() {
|
|
63
|
+
super("Invalid ARID in reference envelope");
|
|
64
|
+
this.name = "InvalidReferenceAridError";
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* No id assertion found in reference envelope.
|
|
69
|
+
*
|
|
70
|
+
* Port of `Error::NoIdAssertion` from hybrid/error.rs line 13-14.
|
|
71
|
+
*
|
|
72
|
+
* @category Hybrid
|
|
73
|
+
*/
|
|
74
|
+
var NoIdAssertionError = class extends HybridError {
|
|
75
|
+
constructor() {
|
|
76
|
+
super("No id assertion found in reference envelope");
|
|
77
|
+
this.name = "NoIdAssertionError";
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/hybrid/reference.ts
|
|
83
|
+
/**
|
|
84
|
+
* Reference envelope utilities for hybrid storage.
|
|
85
|
+
*
|
|
86
|
+
* Port of hybrid/reference.rs from hubert-rust.
|
|
87
|
+
*
|
|
88
|
+
* @module
|
|
89
|
+
*/
|
|
90
|
+
/**
|
|
91
|
+
* Known value for dereferenceVia predicate.
|
|
92
|
+
* @internal
|
|
93
|
+
*/
|
|
94
|
+
const DEREFERENCE_VIA = new _bcts_known_values.KnownValue(8);
|
|
95
|
+
/**
|
|
96
|
+
* Known value for id predicate.
|
|
97
|
+
* @internal
|
|
98
|
+
*/
|
|
99
|
+
const ID = new _bcts_known_values.KnownValue(2);
|
|
100
|
+
/**
|
|
101
|
+
* Creates a reference envelope that points to content stored in IPFS.
|
|
102
|
+
*
|
|
103
|
+
* Reference envelopes are small envelopes stored in the DHT that contain
|
|
104
|
+
* a pointer to the actual envelope stored in IPFS. This allows the hybrid
|
|
105
|
+
* storage layer to transparently handle large envelopes that exceed the
|
|
106
|
+
* DHT size limit.
|
|
107
|
+
*
|
|
108
|
+
* Port of `create_reference_envelope()` from hybrid/reference.rs lines 31-39.
|
|
109
|
+
*
|
|
110
|
+
* # Format
|
|
111
|
+
*
|
|
112
|
+
* ```text
|
|
113
|
+
* '' [
|
|
114
|
+
* 'dereferenceVia': "ipfs",
|
|
115
|
+
* 'id': <ARID>,
|
|
116
|
+
* "size": <number>
|
|
117
|
+
* ]
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @param referenceArid - The ARID used to look up the actual envelope in IPFS
|
|
121
|
+
* @param actualSize - Size of the actual envelope in bytes (for diagnostics)
|
|
122
|
+
* @returns A reference envelope that can be stored in the DHT
|
|
123
|
+
*
|
|
124
|
+
* @category Hybrid
|
|
125
|
+
*/
|
|
126
|
+
function createReferenceEnvelope(referenceArid, actualSize) {
|
|
127
|
+
return _bcts_envelope.Envelope.unit().addAssertion(DEREFERENCE_VIA, "ipfs").addAssertion(ID, referenceArid).addAssertion("size", actualSize);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Checks if an envelope is a reference envelope.
|
|
131
|
+
*
|
|
132
|
+
* A reference envelope contains `dereferenceVia: "ipfs"` and an `id` assertion.
|
|
133
|
+
*
|
|
134
|
+
* Port of `is_reference_envelope()` from hybrid/reference.rs lines 53-91.
|
|
135
|
+
*
|
|
136
|
+
* @param envelope - The envelope to check
|
|
137
|
+
* @returns `true` if this is a reference envelope, `false` otherwise
|
|
138
|
+
*
|
|
139
|
+
* @category Hybrid
|
|
140
|
+
*/
|
|
141
|
+
function isReferenceEnvelope(envelope) {
|
|
142
|
+
if (!envelope.isSubjectUnit) return false;
|
|
143
|
+
const assertions = envelope.assertions();
|
|
144
|
+
let hasDereferenceVia = false;
|
|
145
|
+
let hasId = false;
|
|
146
|
+
for (const assertion of assertions) try {
|
|
147
|
+
const predicateSubject = assertion.predicate().subject();
|
|
148
|
+
if (predicateSubject instanceof _bcts_known_values.KnownValue) {
|
|
149
|
+
const kv = predicateSubject;
|
|
150
|
+
if (kv.value === DEREFERENCE_VIA.value) {
|
|
151
|
+
const objectSubject = assertion.object().subject();
|
|
152
|
+
if (typeof objectSubject === "string" && objectSubject === "ipfs") hasDereferenceVia = true;
|
|
153
|
+
}
|
|
154
|
+
if (kv.value === ID.value) hasId = true;
|
|
155
|
+
}
|
|
156
|
+
} catch {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
return hasDereferenceVia && hasId;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Extracts the reference ARID from a reference envelope.
|
|
163
|
+
*
|
|
164
|
+
* Port of `extract_reference_arid()` from hybrid/reference.rs lines 104-129.
|
|
165
|
+
*
|
|
166
|
+
* @param envelope - The reference envelope
|
|
167
|
+
* @returns The reference ARID
|
|
168
|
+
* @throws {NotReferenceEnvelopeError} If the envelope is not a reference envelope
|
|
169
|
+
* @throws {InvalidReferenceAridError} If the ARID cannot be extracted
|
|
170
|
+
* @throws {NoIdAssertionError} If no id assertion is found
|
|
171
|
+
*
|
|
172
|
+
* @category Hybrid
|
|
173
|
+
*/
|
|
174
|
+
function extractReferenceArid(envelope) {
|
|
175
|
+
if (!isReferenceEnvelope(envelope)) throw new NotReferenceEnvelopeError();
|
|
176
|
+
const assertions = envelope.assertions();
|
|
177
|
+
for (const assertion of assertions) try {
|
|
178
|
+
const predicateSubject = assertion.predicate().subject();
|
|
179
|
+
if (predicateSubject instanceof _bcts_known_values.KnownValue) {
|
|
180
|
+
if (predicateSubject.value === ID.value) {
|
|
181
|
+
const objectSubject = assertion.object().subject();
|
|
182
|
+
if (objectSubject instanceof _bcts_components.ARID) return objectSubject;
|
|
183
|
+
throw new InvalidReferenceAridError();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
187
|
+
if (error instanceof NotReferenceEnvelopeError || error instanceof InvalidReferenceAridError || error instanceof NoIdAssertionError) throw error;
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
throw new NoIdAssertionError();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/hybrid/kv.ts
|
|
195
|
+
/**
|
|
196
|
+
* Hybrid storage layer combining Mainline DHT and IPFS.
|
|
197
|
+
*
|
|
198
|
+
* Port of hybrid/kv.rs from hubert-rust.
|
|
199
|
+
*
|
|
200
|
+
* @module
|
|
201
|
+
*/
|
|
202
|
+
/**
|
|
203
|
+
* Hybrid storage layer combining Mainline DHT and IPFS.
|
|
204
|
+
*
|
|
205
|
+
* Automatically optimizes storage based on envelope size:
|
|
206
|
+
* - **Small envelopes (≤1000 bytes)**: Stored directly in DHT
|
|
207
|
+
* - **Large envelopes (>1000 bytes)**: Reference in DHT → actual envelope in IPFS
|
|
208
|
+
*
|
|
209
|
+
* This provides the best of both worlds:
|
|
210
|
+
* - Fast lookups for small messages via DHT
|
|
211
|
+
* - Large capacity for big messages via IPFS
|
|
212
|
+
* - Transparent indirection handled automatically
|
|
213
|
+
*
|
|
214
|
+
* Port of `struct HybridKv` from hybrid/kv.rs lines 59-63.
|
|
215
|
+
*
|
|
216
|
+
* # Requirements
|
|
217
|
+
*
|
|
218
|
+
* - No external daemon for DHT (embedded client)
|
|
219
|
+
* - Requires Kubo daemon for IPFS (http://127.0.0.1:5001)
|
|
220
|
+
*
|
|
221
|
+
* @category Hybrid Backend
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* const store = await HybridKv.create("http://127.0.0.1:5001");
|
|
226
|
+
*
|
|
227
|
+
* // Small envelope → DHT only
|
|
228
|
+
* const arid1 = ARID.new();
|
|
229
|
+
* const small = Envelope.new("Small message");
|
|
230
|
+
* await store.put(arid1, small);
|
|
231
|
+
*
|
|
232
|
+
* // Large envelope → DHT reference + IPFS
|
|
233
|
+
* const arid2 = ARID.new();
|
|
234
|
+
* const large = Envelope.new("x".repeat(2000));
|
|
235
|
+
* await store.put(arid2, large);
|
|
236
|
+
*
|
|
237
|
+
* // Get works the same for both
|
|
238
|
+
* const retrieved1 = await store.get(arid1);
|
|
239
|
+
* const retrieved2 = await store.get(arid2);
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
var HybridKv = class HybridKv {
|
|
243
|
+
dht;
|
|
244
|
+
ipfs;
|
|
245
|
+
dhtSizeLimit;
|
|
246
|
+
/**
|
|
247
|
+
* Private constructor - use `create()` factory method.
|
|
248
|
+
*/
|
|
249
|
+
constructor(dht, ipfs) {
|
|
250
|
+
this.dht = dht;
|
|
251
|
+
this.ipfs = ipfs;
|
|
252
|
+
this.dhtSizeLimit = 1e3;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Create a new Hybrid KV store with default settings.
|
|
256
|
+
*
|
|
257
|
+
* Port of `HybridKv::new()` from hybrid/kv.rs lines 75-84.
|
|
258
|
+
*
|
|
259
|
+
* @param ipfsRpcUrl - IPFS RPC endpoint (e.g., "http://127.0.0.1:5001")
|
|
260
|
+
*/
|
|
261
|
+
static async create(ipfsRpcUrl) {
|
|
262
|
+
return new HybridKv(await require_kv$1.MainlineDhtKv.create(), new require_kv.IpfsKv(ipfsRpcUrl));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Set custom DHT size limit (default: 1000 bytes).
|
|
266
|
+
*
|
|
267
|
+
* Envelopes larger than this will use IPFS indirection.
|
|
268
|
+
*
|
|
269
|
+
* Port of `HybridKv::with_dht_size_limit()` from hybrid/kv.rs lines 89-92.
|
|
270
|
+
*/
|
|
271
|
+
withDhtSizeLimit(limit) {
|
|
272
|
+
this.dhtSizeLimit = limit;
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Set whether to pin content in IPFS (default: false).
|
|
277
|
+
*
|
|
278
|
+
* Only affects envelopes stored in IPFS (when larger than DHT limit).
|
|
279
|
+
*
|
|
280
|
+
* Port of `HybridKv::with_pin_content()` from hybrid/kv.rs lines 97-100.
|
|
281
|
+
*/
|
|
282
|
+
withPinContent(pin) {
|
|
283
|
+
this.ipfs = this.ipfs.withPinContent(pin);
|
|
284
|
+
return this;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Check if an envelope fits in the DHT.
|
|
288
|
+
*
|
|
289
|
+
* Port of `HybridKv::fits_in_dht()` from hybrid/kv.rs lines 103-106.
|
|
290
|
+
*
|
|
291
|
+
* @internal
|
|
292
|
+
*/
|
|
293
|
+
fitsInDht(envelope) {
|
|
294
|
+
return envelope.taggedCborData.length <= this.dhtSizeLimit;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Store an envelope at the given ARID.
|
|
298
|
+
*
|
|
299
|
+
* Port of `KvStore::put()` implementation from hybrid/kv.rs lines 109-168.
|
|
300
|
+
*/
|
|
301
|
+
async put(arid, envelope, ttlSeconds, verbose) {
|
|
302
|
+
if (this.fitsInDht(envelope)) {
|
|
303
|
+
if (verbose) require_logging.verbosePrintln(`Storing envelope in DHT (size ≤ ${this.dhtSizeLimit} bytes)`);
|
|
304
|
+
await this.dht.put(arid, envelope, ttlSeconds, verbose);
|
|
305
|
+
return `Stored in DHT at ARID: ${arid.urString()}`;
|
|
306
|
+
} else {
|
|
307
|
+
if (verbose) require_logging.verbosePrintln("Envelope too large for DHT, using IPFS indirection");
|
|
308
|
+
const referenceArid = _bcts_components.ARID.new();
|
|
309
|
+
if (verbose) require_logging.verbosePrintln(`Storing actual envelope in IPFS with reference ARID: ${referenceArid.urString()}`);
|
|
310
|
+
await this.ipfs.put(referenceArid, envelope, ttlSeconds, verbose);
|
|
311
|
+
const envelopeSize = envelope.taggedCborData.length;
|
|
312
|
+
const reference = createReferenceEnvelope(referenceArid, envelopeSize);
|
|
313
|
+
if (verbose) require_logging.verbosePrintln("Storing reference envelope in DHT at original ARID");
|
|
314
|
+
await this.dht.put(arid, reference, ttlSeconds, verbose);
|
|
315
|
+
return `Stored in IPFS (ref: ${referenceArid.urString()}) via DHT at ARID: ${arid.urString()}`;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Retrieve an envelope for the given ARID.
|
|
320
|
+
*
|
|
321
|
+
* Port of `KvStore::get()` implementation from hybrid/kv.rs lines 171-230.
|
|
322
|
+
*/
|
|
323
|
+
async get(arid, timeoutSeconds, verbose) {
|
|
324
|
+
const dhtEnvelope = await this.dht.get(arid, timeoutSeconds, verbose);
|
|
325
|
+
if (dhtEnvelope === null) return null;
|
|
326
|
+
if (isReferenceEnvelope(dhtEnvelope)) {
|
|
327
|
+
if (verbose) require_logging.verbosePrintln("Found reference envelope, fetching actual envelope from IPFS");
|
|
328
|
+
const referenceArid = extractReferenceArid(dhtEnvelope);
|
|
329
|
+
if (verbose) require_logging.verbosePrintln(`Reference ARID: ${referenceArid.urString()}`);
|
|
330
|
+
const ipfsEnvelope = await this.ipfs.get(referenceArid, timeoutSeconds, verbose);
|
|
331
|
+
if (ipfsEnvelope === null) throw new ContentNotFoundError();
|
|
332
|
+
if (verbose) require_logging.verbosePrintln("Successfully retrieved actual envelope from IPFS");
|
|
333
|
+
return ipfsEnvelope;
|
|
334
|
+
} else {
|
|
335
|
+
if (verbose) require_logging.verbosePrintln("Envelope is not a reference, treating as direct payload");
|
|
336
|
+
return dhtEnvelope;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Check if an envelope exists at the given ARID.
|
|
341
|
+
*
|
|
342
|
+
* Port of `KvStore::exists()` implementation from hybrid/kv.rs lines 254-257.
|
|
343
|
+
*/
|
|
344
|
+
async exists(arid) {
|
|
345
|
+
return await this.dht.exists(arid);
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Destroy the hybrid store and release resources.
|
|
349
|
+
*/
|
|
350
|
+
async destroy() {
|
|
351
|
+
await this.dht.destroy();
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
//#endregion
|
|
356
|
+
Object.defineProperty(exports, 'ContentNotFoundError', {
|
|
357
|
+
enumerable: true,
|
|
358
|
+
get: function () {
|
|
359
|
+
return ContentNotFoundError;
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
Object.defineProperty(exports, 'HybridError', {
|
|
363
|
+
enumerable: true,
|
|
364
|
+
get: function () {
|
|
365
|
+
return HybridError;
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
Object.defineProperty(exports, 'HybridKv', {
|
|
369
|
+
enumerable: true,
|
|
370
|
+
get: function () {
|
|
371
|
+
return HybridKv;
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
Object.defineProperty(exports, 'InvalidReferenceAridError', {
|
|
375
|
+
enumerable: true,
|
|
376
|
+
get: function () {
|
|
377
|
+
return InvalidReferenceAridError;
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
Object.defineProperty(exports, 'NoIdAssertionError', {
|
|
381
|
+
enumerable: true,
|
|
382
|
+
get: function () {
|
|
383
|
+
return NoIdAssertionError;
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
Object.defineProperty(exports, 'NotReferenceEnvelopeError', {
|
|
387
|
+
enumerable: true,
|
|
388
|
+
get: function () {
|
|
389
|
+
return NotReferenceEnvelopeError;
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
Object.defineProperty(exports, 'createReferenceEnvelope', {
|
|
393
|
+
enumerable: true,
|
|
394
|
+
get: function () {
|
|
395
|
+
return createReferenceEnvelope;
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
Object.defineProperty(exports, 'extractReferenceArid', {
|
|
399
|
+
enumerable: true,
|
|
400
|
+
get: function () {
|
|
401
|
+
return extractReferenceArid;
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
Object.defineProperty(exports, 'isReferenceEnvelope', {
|
|
405
|
+
enumerable: true,
|
|
406
|
+
get: function () {
|
|
407
|
+
return isReferenceEnvelope;
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
//# sourceMappingURL=hybrid-dX5JLumO.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hybrid-dX5JLumO.cjs","names":["HubertError","KnownValue","Envelope","ARID","MainlineDhtKv","IpfsKv","ARID"],"sources":["../src/hybrid/error.ts","../src/hybrid/reference.ts","../src/hybrid/kv.ts"],"sourcesContent":["/**\n * Hybrid-specific errors.\n *\n * Port of hybrid/error.rs from hubert-rust.\n *\n * @module\n */\n\nimport { HubertError } from \"../error.js\";\n\n/**\n * Base class for Hybrid-specific errors.\n *\n * @category Hybrid\n */\nexport class HybridError extends HubertError {\n constructor(message: string) {\n super(message);\n this.name = \"HybridError\";\n }\n}\n\n/**\n * Referenced IPFS content not found.\n *\n * Port of `Error::ContentNotFound` from hybrid/error.rs line 4-5.\n *\n * @category Hybrid\n */\nexport class ContentNotFoundError extends HybridError {\n constructor() {\n super(\"Referenced IPFS content not found\");\n this.name = \"ContentNotFoundError\";\n }\n}\n\n/**\n * Not a reference envelope.\n *\n * Port of `Error::NotReferenceEnvelope` from hybrid/error.rs line 7-8.\n *\n * @category Hybrid\n */\nexport class NotReferenceEnvelopeError extends HybridError {\n constructor() {\n super(\"Not a reference envelope\");\n this.name = \"NotReferenceEnvelopeError\";\n }\n}\n\n/**\n * Invalid ARID in reference envelope.\n *\n * Port of `Error::InvalidReferenceArid` from hybrid/error.rs line 10-11.\n *\n * @category Hybrid\n */\nexport class InvalidReferenceAridError extends HybridError {\n constructor() {\n super(\"Invalid ARID in reference envelope\");\n this.name = \"InvalidReferenceAridError\";\n }\n}\n\n/**\n * No id assertion found in reference envelope.\n *\n * Port of `Error::NoIdAssertion` from hybrid/error.rs line 13-14.\n *\n * @category Hybrid\n */\nexport class NoIdAssertionError extends HybridError {\n constructor() {\n super(\"No id assertion found in reference envelope\");\n this.name = \"NoIdAssertionError\";\n }\n}\n","/**\n * Reference envelope utilities for hybrid storage.\n *\n * Port of hybrid/reference.rs from hubert-rust.\n *\n * @module\n */\n\nimport { ARID } from \"@bcts/components\";\nimport { Envelope } from \"@bcts/envelope\";\nimport { KnownValue } from \"@bcts/known-values\";\n\nimport {\n InvalidReferenceAridError,\n NoIdAssertionError,\n NotReferenceEnvelopeError,\n} from \"./error.js\";\n\n/**\n * Known value for dereferenceVia predicate.\n * @internal\n */\nconst DEREFERENCE_VIA = new KnownValue(8);\n\n/**\n * Known value for id predicate.\n * @internal\n */\nconst ID = new KnownValue(2);\n\n/**\n * Creates a reference envelope that points to content stored in IPFS.\n *\n * Reference envelopes are small envelopes stored in the DHT that contain\n * a pointer to the actual envelope stored in IPFS. This allows the hybrid\n * storage layer to transparently handle large envelopes that exceed the\n * DHT size limit.\n *\n * Port of `create_reference_envelope()` from hybrid/reference.rs lines 31-39.\n *\n * # Format\n *\n * ```text\n * '' [\n * 'dereferenceVia': \"ipfs\",\n * 'id': <ARID>,\n * \"size\": <number>\n * ]\n * ```\n *\n * @param referenceArid - The ARID used to look up the actual envelope in IPFS\n * @param actualSize - Size of the actual envelope in bytes (for diagnostics)\n * @returns A reference envelope that can be stored in the DHT\n *\n * @category Hybrid\n */\nexport function createReferenceEnvelope(referenceArid: ARID, actualSize: number): Envelope {\n return Envelope.unit()\n .addAssertion(DEREFERENCE_VIA, \"ipfs\")\n .addAssertion(ID, referenceArid)\n .addAssertion(\"size\", actualSize);\n}\n\n/**\n * Checks if an envelope is a reference envelope.\n *\n * A reference envelope contains `dereferenceVia: \"ipfs\"` and an `id` assertion.\n *\n * Port of `is_reference_envelope()` from hybrid/reference.rs lines 53-91.\n *\n * @param envelope - The envelope to check\n * @returns `true` if this is a reference envelope, `false` otherwise\n *\n * @category Hybrid\n */\nexport function isReferenceEnvelope(envelope: Envelope): boolean {\n // Check if subject is the unit value\n if (!envelope.isSubjectUnit) {\n return false;\n }\n\n const assertions = envelope.assertions();\n\n // Check for dereferenceVia: \"ipfs\" assertion\n let hasDereferenceVia = false;\n let hasId = false;\n\n for (const assertion of assertions) {\n try {\n const predicate = assertion.predicate();\n\n // Check if predicate is a known value\n const predicateSubject = predicate.subject();\n if (predicateSubject instanceof KnownValue) {\n const kv = predicateSubject;\n\n // Check for dereferenceVia\n if (kv.value === DEREFERENCE_VIA.value) {\n const object = assertion.object();\n const objectSubject = object.subject();\n if (typeof objectSubject === \"string\" && objectSubject === \"ipfs\") {\n hasDereferenceVia = true;\n }\n }\n\n // Check for id\n if (kv.value === ID.value) {\n hasId = true;\n }\n }\n } catch {\n // Skip assertions that can't be parsed\n continue;\n }\n }\n\n return hasDereferenceVia && hasId;\n}\n\n/**\n * Extracts the reference ARID from a reference envelope.\n *\n * Port of `extract_reference_arid()` from hybrid/reference.rs lines 104-129.\n *\n * @param envelope - The reference envelope\n * @returns The reference ARID\n * @throws {NotReferenceEnvelopeError} If the envelope is not a reference envelope\n * @throws {InvalidReferenceAridError} If the ARID cannot be extracted\n * @throws {NoIdAssertionError} If no id assertion is found\n *\n * @category Hybrid\n */\nexport function extractReferenceArid(envelope: Envelope): ARID {\n if (!isReferenceEnvelope(envelope)) {\n throw new NotReferenceEnvelopeError();\n }\n\n const assertions = envelope.assertions();\n\n // Find the id assertion and extract the ARID\n for (const assertion of assertions) {\n try {\n const predicate = assertion.predicate();\n const predicateSubject = predicate.subject();\n\n if (predicateSubject instanceof KnownValue) {\n const kv = predicateSubject;\n\n // Check for id\n if (kv.value === ID.value) {\n const object = assertion.object();\n const objectSubject = object.subject();\n\n if (objectSubject instanceof ARID) {\n return objectSubject;\n }\n\n // Try to extract ARID from CBOR\n throw new InvalidReferenceAridError();\n }\n }\n } catch (error) {\n if (\n error instanceof NotReferenceEnvelopeError ||\n error instanceof InvalidReferenceAridError ||\n error instanceof NoIdAssertionError\n ) {\n throw error;\n }\n // Continue searching\n continue;\n }\n }\n\n throw new NoIdAssertionError();\n}\n","/**\n * Hybrid storage layer combining Mainline DHT and IPFS.\n *\n * Port of hybrid/kv.rs from hubert-rust.\n *\n * @module\n */\n\nimport { ARID } from \"@bcts/components\";\nimport { type Envelope } from \"@bcts/envelope\";\n\nimport { type KvStore } from \"../kv-store.js\";\nimport { verbosePrintln } from \"../logging.js\";\nimport { IpfsKv } from \"../ipfs/kv.js\";\nimport { MainlineDhtKv } from \"../mainline/kv.js\";\nimport { ContentNotFoundError } from \"./error.js\";\nimport { createReferenceEnvelope, extractReferenceArid, isReferenceEnvelope } from \"./reference.js\";\n\n/**\n * Hybrid storage layer combining Mainline DHT and IPFS.\n *\n * Automatically optimizes storage based on envelope size:\n * - **Small envelopes (≤1000 bytes)**: Stored directly in DHT\n * - **Large envelopes (>1000 bytes)**: Reference in DHT → actual envelope in IPFS\n *\n * This provides the best of both worlds:\n * - Fast lookups for small messages via DHT\n * - Large capacity for big messages via IPFS\n * - Transparent indirection handled automatically\n *\n * Port of `struct HybridKv` from hybrid/kv.rs lines 59-63.\n *\n * # Requirements\n *\n * - No external daemon for DHT (embedded client)\n * - Requires Kubo daemon for IPFS (http://127.0.0.1:5001)\n *\n * @category Hybrid Backend\n *\n * @example\n * ```typescript\n * const store = await HybridKv.create(\"http://127.0.0.1:5001\");\n *\n * // Small envelope → DHT only\n * const arid1 = ARID.new();\n * const small = Envelope.new(\"Small message\");\n * await store.put(arid1, small);\n *\n * // Large envelope → DHT reference + IPFS\n * const arid2 = ARID.new();\n * const large = Envelope.new(\"x\".repeat(2000));\n * await store.put(arid2, large);\n *\n * // Get works the same for both\n * const retrieved1 = await store.get(arid1);\n * const retrieved2 = await store.get(arid2);\n * ```\n */\nexport class HybridKv implements KvStore {\n private readonly dht: MainlineDhtKv;\n private ipfs: IpfsKv;\n private dhtSizeLimit: number;\n\n /**\n * Private constructor - use `create()` factory method.\n */\n private constructor(dht: MainlineDhtKv, ipfs: IpfsKv) {\n this.dht = dht;\n this.ipfs = ipfs;\n this.dhtSizeLimit = 1000; // Conservative DHT limit\n }\n\n /**\n * Create a new Hybrid KV store with default settings.\n *\n * Port of `HybridKv::new()` from hybrid/kv.rs lines 75-84.\n *\n * @param ipfsRpcUrl - IPFS RPC endpoint (e.g., \"http://127.0.0.1:5001\")\n */\n static async create(ipfsRpcUrl: string): Promise<HybridKv> {\n const dht = await MainlineDhtKv.create();\n const ipfs = new IpfsKv(ipfsRpcUrl);\n\n return new HybridKv(dht, ipfs);\n }\n\n /**\n * Set custom DHT size limit (default: 1000 bytes).\n *\n * Envelopes larger than this will use IPFS indirection.\n *\n * Port of `HybridKv::with_dht_size_limit()` from hybrid/kv.rs lines 89-92.\n */\n withDhtSizeLimit(limit: number): this {\n this.dhtSizeLimit = limit;\n return this;\n }\n\n /**\n * Set whether to pin content in IPFS (default: false).\n *\n * Only affects envelopes stored in IPFS (when larger than DHT limit).\n *\n * Port of `HybridKv::with_pin_content()` from hybrid/kv.rs lines 97-100.\n */\n withPinContent(pin: boolean): this {\n this.ipfs = this.ipfs.withPinContent(pin);\n return this;\n }\n\n /**\n * Check if an envelope fits in the DHT.\n *\n * Port of `HybridKv::fits_in_dht()` from hybrid/kv.rs lines 103-106.\n *\n * @internal\n */\n private fitsInDht(envelope: Envelope): boolean {\n const serialized = envelope.taggedCborData;\n return serialized.length <= this.dhtSizeLimit;\n }\n\n /**\n * Store an envelope at the given ARID.\n *\n * Port of `KvStore::put()` implementation from hybrid/kv.rs lines 109-168.\n */\n async put(\n arid: ARID,\n envelope: Envelope,\n ttlSeconds?: number,\n verbose?: boolean,\n ): Promise<string> {\n // Check if it fits in DHT\n if (this.fitsInDht(envelope)) {\n // Store directly in DHT (DHT handles obfuscation)\n if (verbose) {\n verbosePrintln(`Storing envelope in DHT (size ≤ ${this.dhtSizeLimit} bytes)`);\n }\n await this.dht.put(arid, envelope, ttlSeconds, verbose);\n return `Stored in DHT at ARID: ${arid.urString()}`;\n } else {\n // Use IPFS with DHT reference\n if (verbose) {\n verbosePrintln(\"Envelope too large for DHT, using IPFS indirection\");\n }\n\n // 1. Store actual envelope in IPFS with a new ARID\n // (IPFS handles obfuscation with reference_arid)\n const referenceArid = ARID.new();\n if (verbose) {\n verbosePrintln(\n `Storing actual envelope in IPFS with reference ARID: ${referenceArid.urString()}`,\n );\n }\n await this.ipfs.put(referenceArid, envelope, ttlSeconds, verbose);\n\n // 2. Create reference envelope\n const envelopeSize = envelope.taggedCborData.length;\n const reference = createReferenceEnvelope(referenceArid, envelopeSize);\n\n // 3. Store reference envelope in DHT at original ARID\n // (DHT handles obfuscation with original arid)\n if (verbose) {\n verbosePrintln(\"Storing reference envelope in DHT at original ARID\");\n }\n await this.dht.put(arid, reference, ttlSeconds, verbose);\n\n return `Stored in IPFS (ref: ${referenceArid.urString()}) via DHT at ARID: ${arid.urString()}`;\n }\n }\n\n /**\n * Retrieve an envelope for the given ARID.\n *\n * Port of `KvStore::get()` implementation from hybrid/kv.rs lines 171-230.\n */\n async get(arid: ARID, timeoutSeconds?: number, verbose?: boolean): Promise<Envelope | null> {\n // 1. Try to get from DHT (DHT handles deobfuscation)\n const dhtEnvelope = await this.dht.get(arid, timeoutSeconds, verbose);\n\n if (dhtEnvelope === null) {\n return null;\n }\n\n // 2. Check if the envelope is a reference envelope\n if (isReferenceEnvelope(dhtEnvelope)) {\n if (verbose) {\n verbosePrintln(\"Found reference envelope, fetching actual envelope from IPFS\");\n }\n\n // 3. Extract reference ARID\n const referenceArid = extractReferenceArid(dhtEnvelope);\n\n if (verbose) {\n verbosePrintln(`Reference ARID: ${referenceArid.urString()}`);\n }\n\n // 4. Retrieve actual envelope from IPFS\n // (IPFS handles deobfuscation with reference_arid)\n const ipfsEnvelope = await this.ipfs.get(referenceArid, timeoutSeconds, verbose);\n\n if (ipfsEnvelope === null) {\n throw new ContentNotFoundError();\n }\n\n if (verbose) {\n verbosePrintln(\"Successfully retrieved actual envelope from IPFS\");\n }\n return ipfsEnvelope;\n } else {\n // Not a reference envelope, return it directly\n if (verbose) {\n verbosePrintln(\"Envelope is not a reference, treating as direct payload\");\n }\n return dhtEnvelope;\n }\n }\n\n /**\n * Check if an envelope exists at the given ARID.\n *\n * Port of `KvStore::exists()` implementation from hybrid/kv.rs lines 254-257.\n */\n async exists(arid: ARID): Promise<boolean> {\n // Check DHT only (references count as existing)\n return await this.dht.exists(arid);\n }\n\n /**\n * Destroy the hybrid store and release resources.\n */\n async destroy(): Promise<void> {\n await this.dht.destroy();\n }\n}\n"],"mappings":"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"}
|