pikelet-wasm 0.9.2 → 0.9.3
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/CHANGELOG.md +61 -0
- package/complete/builder.d.ts +4 -0
- package/complete/builder.mjs +14 -4
- package/complete/index.d.ts +7 -1
- package/complete/index.mjs +18 -8
- package/complete/lexical.mjs +14 -0
- package/complete/retrieval-abstention.mjs +14 -0
- package/package.json +1 -1
- package/src/artifact/pikelet-artifact-sketch.js +31 -1
- package/src/artifact/pikelet-artifact.d.ts +7 -0
- package/src/artifact/pikelet-artifact.js +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,67 @@ Through 0.6.0 these were published as `pancake-wasm` and
|
|
|
8
8
|
packages are pre-1.0: a minor bump may carry breaking changes, and each entry lists them
|
|
9
9
|
first.
|
|
10
10
|
|
|
11
|
+
## pikelet-wasm 0.9.3 / pikelet 0.9.3 — 2026-10-06
|
|
12
|
+
|
|
13
|
+
Hardening for readers that mount packs from other publishers or hosts:
|
|
14
|
+
the index header commitment now covers the bytes actually parsed, and a
|
|
15
|
+
pack can no longer steer lazy reads, demand an exhaustive rerank, or turn
|
|
16
|
+
a malformed abstention asset into confident answers. Upgrade if you mount
|
|
17
|
+
packs you did not build, including over `pikelet mcp`. Both packages move
|
|
18
|
+
to 0.9.3 together, and `pikelet` requires `pikelet-wasm` ^0.9.3 so that
|
|
19
|
+
`pikelet mcp` serves through the hardened reader.
|
|
20
|
+
|
|
21
|
+
### Compatibility
|
|
22
|
+
|
|
23
|
+
- **A pack that declares a rerank depth over 4096 is served at 4096 by
|
|
24
|
+
default**, unless the caller passes `rerank`. No published pack is
|
|
25
|
+
affected.
|
|
26
|
+
- **A pack whose abstention asset has malformed `thresholds` or
|
|
27
|
+
`coverage.topK` now reports `unscored`** instead of answering. Packs
|
|
28
|
+
built by `compile` are not affected.
|
|
29
|
+
- **`compile` declares at most 4096** for a pack over 4096 records whose
|
|
30
|
+
sweep does not meet its recall target, and warns. Other packs compile
|
|
31
|
+
as under 0.9.2.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- **The index header commitment binds the bytes the reader parses.** The
|
|
36
|
+
complete reader checked `manifest.index.headerSha256` on its own read of
|
|
37
|
+
the sketch header, while the sketch parsed a separate read of the same
|
|
38
|
+
range. A host answering the two reads differently could pass the check
|
|
39
|
+
with the genuine header and have a forged one parsed, together with the
|
|
40
|
+
integrity anchors it carries, replacing the index under a pinned
|
|
41
|
+
identity. `PikeletSketchArtifact.open()` now takes
|
|
42
|
+
`expectedHeaderSha256` and checks the header it parses.
|
|
43
|
+
- **Lazily read keyword segments cannot steer reads or inflate them.**
|
|
44
|
+
Lexical segments over 8 MiB are read on demand without per-read
|
|
45
|
+
verification. Reads are now confined to the segment's window, and each
|
|
46
|
+
term entry is checked before its postings are fetched: inside the
|
|
47
|
+
postings region, `df` no larger than the corpus, and a length a postings
|
|
48
|
+
list of that `df` can occupy. `info().lexical.integrity` reports
|
|
49
|
+
`'unverified-lazy-reads'` for such segments and `'segment-sha256'` for
|
|
50
|
+
eagerly verified ones.
|
|
51
|
+
- **A pack's declared rerank depth is capped at 4096 by default.** The
|
|
52
|
+
sketch header's `recommendedRerank` is a producer hint; a value near the
|
|
53
|
+
row count made every query fetch, hash and rerank the whole vectors
|
|
54
|
+
region. Readers default to at most 4096, keep the declared value as
|
|
55
|
+
`declaredRecommendedRerank`, and still honor an explicit `rerank`. The
|
|
56
|
+
published wiki, astro-docs and rust-book packs declare 200, 40 and 30.
|
|
57
|
+
- **`compile` and `append` no longer declare a rerank depth readers will not
|
|
58
|
+
use.** `compile`'s rerank sweep fell back to the full row count when no
|
|
59
|
+
depth up to 640 met its recall target; it now stops at the same 4096
|
|
60
|
+
ceiling, records the recall measured there, and logs a warning when the
|
|
61
|
+
target was not met. `append` caps a layer's exhaustive hint the same way.
|
|
62
|
+
`measureRecommendedRerank` returns `targetReached` and `rerankCeiling`,
|
|
63
|
+
and `pikelet-wasm/artifact` exports `MAX_RECOMMENDED_RERANK`.
|
|
64
|
+
- **A malformed abstention asset serves `unscored`.** Missing or
|
|
65
|
+
non-numeric `thresholds` compared false against every score, so the pack
|
|
66
|
+
answered every query as if calibrated; out-of-order or out-of-range ones
|
|
67
|
+
gave verdicts the fit never defined. A `coverage.topK` outside 1–10 is
|
|
68
|
+
refused too, since each counted passage is a record read on every query.
|
|
69
|
+
The scorer now rejects such an asset and the pack reports `unscored`.
|
|
70
|
+
Assets written by `compile` are unaffected.
|
|
71
|
+
|
|
11
72
|
## pikelet-wasm 0.9.2 / pikelet 0.9.2 — 2026-10-01
|
|
12
73
|
|
|
13
74
|
Makes the layered update path work as documented: `append` on a freshly
|
package/complete/builder.d.ts
CHANGED
|
@@ -71,6 +71,10 @@ export declare function measureRecommendedRerank(input: {
|
|
|
71
71
|
}): Promise<{
|
|
72
72
|
recommendedRerank: number;
|
|
73
73
|
recall: number;
|
|
74
|
+
/** False when no rung up to rerankCeiling reached targetRecall; recommendedRerank is then the ceiling. */
|
|
75
|
+
targetReached: boolean;
|
|
76
|
+
/** min(row count, MAX_RECOMMENDED_RERANK): the deepest rerank the sweep measures. */
|
|
77
|
+
rerankCeiling: number;
|
|
74
78
|
k: number;
|
|
75
79
|
targetRecall: number;
|
|
76
80
|
queries: number;
|
package/complete/builder.mjs
CHANGED
|
@@ -351,6 +351,12 @@ export function buildInlineTransformerEncoderSegment({ declaration, vocabBytes,
|
|
|
351
351
|
// targetRecall — plus the whole curve for the evaluation segment. Queries
|
|
352
352
|
// are the corpus's own float embeddings when the caller has them, else rows
|
|
353
353
|
// dequantized out of the snapshot.
|
|
354
|
+
//
|
|
355
|
+
// The sweep stops at the reader's default ceiling (MAX_RECOMMENDED_RERANK):
|
|
356
|
+
// it used to fall back to the full row count, a depth readers no longer
|
|
357
|
+
// honor by default, so a pack could record a recall it would not be served
|
|
358
|
+
// at. The last rung is the ceiling, measured like any other, and
|
|
359
|
+
// targetReached says whether the target was met below it.
|
|
354
360
|
export async function measureRecommendedRerank({
|
|
355
361
|
artifactModule,
|
|
356
362
|
sketchBytes,
|
|
@@ -387,9 +393,10 @@ export async function measureRecommendedRerank({
|
|
|
387
393
|
for (const q of queries) {
|
|
388
394
|
truth.push(new Set((await sketch.search(q, topK, { rerank: count })).results.map((r) => r.id)));
|
|
389
395
|
}
|
|
396
|
+
const rerankCeiling = Math.min(count, artifactModule.MAX_RECOMMENDED_RERANK ?? count);
|
|
390
397
|
const ladder = (sweep || [10, 15, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480, 640])
|
|
391
|
-
.filter((c) => c >= topK && c <
|
|
392
|
-
ladder.push(
|
|
398
|
+
.filter((c) => c >= topK && c < rerankCeiling);
|
|
399
|
+
ladder.push(rerankCeiling);
|
|
393
400
|
const curve = [];
|
|
394
401
|
let recommendedRerank = null;
|
|
395
402
|
let recommendedRecall = null;
|
|
@@ -409,13 +416,16 @@ export async function measureRecommendedRerank({
|
|
|
409
416
|
recommendedRecall = recall;
|
|
410
417
|
}
|
|
411
418
|
}
|
|
412
|
-
|
|
413
|
-
|
|
419
|
+
const targetReached = recommendedRerank !== null;
|
|
420
|
+
if (!targetReached) {
|
|
421
|
+
recommendedRerank = rerankCeiling;
|
|
414
422
|
recommendedRecall = curve[curve.length - 1].recall;
|
|
415
423
|
}
|
|
416
424
|
return {
|
|
417
425
|
recommendedRerank,
|
|
418
426
|
recall: recommendedRecall,
|
|
427
|
+
targetReached,
|
|
428
|
+
rerankCeiling,
|
|
419
429
|
k: topK,
|
|
420
430
|
targetRecall,
|
|
421
431
|
queries: queries.length,
|
package/complete/index.d.ts
CHANGED
|
@@ -134,7 +134,13 @@ export interface CompleteSearch {
|
|
|
134
134
|
* order fuses distance and BM25 rankings by reciprocal rank). Null on
|
|
135
135
|
* vector-only artifacts.
|
|
136
136
|
*/
|
|
137
|
-
lexical: {
|
|
137
|
+
lexical: {
|
|
138
|
+
terms: number;
|
|
139
|
+
docCount: number;
|
|
140
|
+
/** 'segment-sha256' when read eagerly and verified whole; 'unverified-lazy-reads' for lazily opened segments. */
|
|
141
|
+
integrity: 'segment-sha256' | 'unverified-lazy-reads';
|
|
142
|
+
lazy?: true;
|
|
143
|
+
} | null;
|
|
138
144
|
/**
|
|
139
145
|
* 'engine' once a WASM scan kernel serves the resident scan
|
|
140
146
|
* (auto-staged or injected via options.sketchScanner); 'js' before
|
package/complete/index.mjs
CHANGED
|
@@ -780,7 +780,12 @@ export async function openPikeletFile(input, options = {}) {
|
|
|
780
780
|
}
|
|
781
781
|
return bytes;
|
|
782
782
|
})(),
|
|
783
|
-
|
|
783
|
+
// Format 2's header commitment is checked inside open(), against
|
|
784
|
+
// the same bytes the sketch parses (see expectedHeaderSha256).
|
|
785
|
+
PikeletSketchArtifact.open(windowSource(source, idx.offset, idx.length), {
|
|
786
|
+
maxReadBytes,
|
|
787
|
+
...(perRecord ? { expectedHeaderSha256: manifest.index.headerSha256 } : {}),
|
|
788
|
+
}),
|
|
784
789
|
readChecked(source, corpus.offset, tablesBytes, 'corpus tables', maxReadBytes, fileBytes),
|
|
785
790
|
// Lexical index (kind 5, OPTIONAL). Small segments: eager
|
|
786
791
|
// whole-segment read, digest-verified like the query-interp
|
|
@@ -791,7 +796,15 @@ export async function openPikeletFile(input, options = {}) {
|
|
|
791
796
|
segments.has('lexical') ? (async () => {
|
|
792
797
|
const seg = segments.get('lexical');
|
|
793
798
|
if (seg.length > LAZY_LEXICAL_BYTES) {
|
|
794
|
-
|
|
799
|
+
// Confined to the segment's own window: lazy reads are
|
|
800
|
+
// not individually verified, so no field they carry may
|
|
801
|
+
// steer a read into another segment.
|
|
802
|
+
const lexRead = (off, len) => {
|
|
803
|
+
if (!Number.isSafeInteger(off) || !Number.isSafeInteger(len) || off < 0 || len < 0 || off + len > seg.length) {
|
|
804
|
+
throw new Error('.pikelet lexical segment read is outside the segment window');
|
|
805
|
+
}
|
|
806
|
+
return readChecked(source, seg.offset + off, len, 'lexical segment', maxReadBytes, fileBytes);
|
|
807
|
+
};
|
|
795
808
|
return { lazyIndex: await openLexicalIndexLazy(lexRead, seg.length) };
|
|
796
809
|
}
|
|
797
810
|
const bytes = await readChecked(source, seg.offset, seg.length, 'lexical segment', maxReadBytes, fileBytes);
|
|
@@ -800,12 +813,6 @@ export async function openPikeletFile(input, options = {}) {
|
|
|
800
813
|
}
|
|
801
814
|
return { bytes };
|
|
802
815
|
})() : null,
|
|
803
|
-
perRecord ? (async () => {
|
|
804
|
-
const headerBytes = await readChecked(source, idx.offset, SKETCH_HEADER_BYTES, 'index header', maxReadBytes, fileBytes);
|
|
805
|
-
if (await sha256hex(headerBytes) !== manifest.index.headerSha256) {
|
|
806
|
-
throw new Error('.pikelet index header failed hash verification against the manifest');
|
|
807
|
-
}
|
|
808
|
-
})() : null,
|
|
809
816
|
]);
|
|
810
817
|
|
|
811
818
|
const lexicalIndex = lexicalBytes
|
|
@@ -1289,6 +1296,9 @@ export async function openPikeletFile(input, options = {}) {
|
|
|
1289
1296
|
? {
|
|
1290
1297
|
terms: lexicalIndex.termCount,
|
|
1291
1298
|
docCount: lexicalIndex.docCount,
|
|
1299
|
+
// Lazy reads are bounded to the segment but not
|
|
1300
|
+
// individually verified (LAZY_LEXICAL_BYTES).
|
|
1301
|
+
integrity: lexicalIndex.lazy ? 'unverified-lazy-reads' : 'segment-sha256',
|
|
1292
1302
|
...(lexicalIndex.lazy ? { lazy: true } : {}),
|
|
1293
1303
|
}
|
|
1294
1304
|
: null,
|
package/complete/lexical.mjs
CHANGED
|
@@ -181,6 +181,20 @@ export async function openLexicalIndexLazy(read, segLength) {
|
|
|
181
181
|
return e && { ...e, term: t };
|
|
182
182
|
}))).filter(Boolean);
|
|
183
183
|
if (!found.length) return [];
|
|
184
|
+
// Term entries arrive by lazy read, unverified (see the stance
|
|
185
|
+
// note above), so each one is held to the segment before its
|
|
186
|
+
// postings are fetched: inside the postings region (spec 3.8, as
|
|
187
|
+
// the eager reader enforces), a df no larger than the corpus, and
|
|
188
|
+
// a length a df-entry list can actually occupy (a doc-gap and a
|
|
189
|
+
// tf varint, each at most 6 bytes). Without these, one forged
|
|
190
|
+
// entry could steer a read anywhere in the file or ask for
|
|
191
|
+
// hundreds of MiB per query term.
|
|
192
|
+
for (const e of found) {
|
|
193
|
+
if (!Number.isSafeInteger(e.postingsRel) || e.postingsRel + e.postingsLen > postingsBytes
|
|
194
|
+
|| e.df > docCount || e.postingsLen > 12 * e.df) {
|
|
195
|
+
throw new Error('.pikelet lexical postings out of bounds');
|
|
196
|
+
}
|
|
197
|
+
}
|
|
184
198
|
const postings = await Promise.all(found.map((e) => read(postingsOffset + e.postingsRel, e.postingsLen)));
|
|
185
199
|
const scores = new Map();
|
|
186
200
|
found.forEach((e, i) => {
|
|
@@ -34,11 +34,25 @@
|
|
|
34
34
|
// one — there is no scenario where re-adding this via a config flag was
|
|
35
35
|
// going to end differently a third time.
|
|
36
36
|
|
|
37
|
+
// Upper bound on asset.coverage.topK. calibrate.mjs ships 5; every passage
|
|
38
|
+
// counted here is a record hydrated on every query, so a pack must not be
|
|
39
|
+
// able to turn one query into a hydration of its whole rerank window.
|
|
40
|
+
export const MAX_COVERAGE_TOP_K = 10;
|
|
41
|
+
|
|
37
42
|
export function createAbstentionScorer(asset, bloomBytes) {
|
|
38
43
|
if (!asset || !Array.isArray(asset.weights) || !asset.thresholds) return null;
|
|
44
|
+
// Thresholds that are missing, non-numeric or out of order compare false
|
|
45
|
+
// against every p and would answer everything; a malformed asset must
|
|
46
|
+
// degrade to unscored instead (callers map a null scorer to it).
|
|
47
|
+
const { hard, weak } = asset.thresholds;
|
|
48
|
+
if (!Number.isFinite(hard) || !Number.isFinite(weak) || hard < 0 || hard > weak || weak > 1) return null;
|
|
39
49
|
const coverageCfg = asset.coverage && typeof asset.coverage.weight === 'number'
|
|
40
50
|
&& Number.isFinite(asset.coverage.mean) && Number.isFinite(asset.coverage.std)
|
|
41
51
|
? asset.coverage : null;
|
|
52
|
+
if (coverageCfg && coverageCfg.topK !== undefined
|
|
53
|
+
&& !(Number.isInteger(coverageCfg.topK) && coverageCfg.topK >= 1 && coverageCfg.topK <= MAX_COVERAGE_TOP_K)) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
42
56
|
const coverageStopwords = coverageCfg ? new Set(coverageCfg.stopwords || []) : null;
|
|
43
57
|
const coverageMinLen = coverageCfg ? (coverageCfg.minWordLen || 3) : 3;
|
|
44
58
|
// Words the corpus uses everywhere ground any query that mentions them,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pikelet-wasm",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.3",
|
|
4
4
|
"description": "Vector search engine and .pikelet artifact readers/builders, in WebAssembly. Compile a corpus into one self-contained, hash-verified search file, or use the underlying HNSW engine directly. Runs in Node.js, browsers, and Cloudflare Workers with no native dependencies.",
|
|
5
5
|
"main": "src/pikelet.js",
|
|
6
6
|
"types": "src/pikelet.d.ts",
|
|
@@ -37,6 +37,12 @@ const {
|
|
|
37
37
|
const SKETCH_MAGIC = 0x31415350; // PSA1
|
|
38
38
|
const SKETCH_HEADER_BYTES = 256;
|
|
39
39
|
const SKETCH_KIND_U8 = 1;
|
|
40
|
+
// Ceiling on the header's recommendedRerank as a reader default. The field
|
|
41
|
+
// is a producer hint, and a hostile (or exhaustive-fallback) value up to the
|
|
42
|
+
// row count would make every query fetch, hash and rerank the whole vectors
|
|
43
|
+
// region — at wiki scale, minutes per query with every check passing. An
|
|
44
|
+
// explicit options.rerank is the caller's own choice and is not capped here.
|
|
45
|
+
const MAX_RECOMMENDED_RERANK = 4096;
|
|
40
46
|
|
|
41
47
|
// The affine table feeds every rerank distance; a NaN/Infinity entry makes
|
|
42
48
|
// that row's distance non-finite and lets it sit in the result set
|
|
@@ -331,6 +337,28 @@ class PikeletSketchArtifact {
|
|
|
331
337
|
if (header.byteLength !== SKETCH_HEADER_BYTES) {
|
|
332
338
|
throw pikeletError(PIKELET_ERROR_CODES.SNAPSHOT_INVALID, 'Sketch artifact header is truncated');
|
|
333
339
|
}
|
|
340
|
+
// options.expectedHeaderSha256 (hex): a container that commits to this
|
|
341
|
+
// header (the complete profile's manifest.index.headerSha256) checks
|
|
342
|
+
// it HERE, against the very bytes parsed below. Checking a separate
|
|
343
|
+
// read instead would let a host serve the genuine header to that read
|
|
344
|
+
// and a rewritten one (with a self-consistent residentSha256 and page
|
|
345
|
+
// table) to this one, replacing the index under a pinned identity.
|
|
346
|
+
if (options.expectedHeaderSha256 !== undefined) {
|
|
347
|
+
const expected = options.expectedHeaderSha256;
|
|
348
|
+
if (typeof expected !== 'string' || !/^[0-9a-f]{64}$/.test(expected)) {
|
|
349
|
+
throw pikeletError(PIKELET_ERROR_CODES.INVALID_ARGUMENT, 'SketchArtifact.open() expectedHeaderSha256 must be 64 lowercase hex characters');
|
|
350
|
+
}
|
|
351
|
+
const digest = await sha256BytesAsync(header);
|
|
352
|
+
if (!digest) {
|
|
353
|
+
throw pikeletError(PIKELET_ERROR_CODES.SNAPSHOT_INVALID,
|
|
354
|
+
'Sketch artifact header verification requested but no crypto backend is available');
|
|
355
|
+
}
|
|
356
|
+
let hex = '';
|
|
357
|
+
for (const b of digest) hex += b.toString(16).padStart(2, '0');
|
|
358
|
+
if (hex !== expected) {
|
|
359
|
+
throw pikeletError(PIKELET_ERROR_CODES.SNAPSHOT_INVALID, '.pikelet index header failed hash verification against the manifest');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
334
362
|
const view = new DataView(header.buffer, header.byteOffset, header.byteLength);
|
|
335
363
|
if (view.getUint32(0, true) !== SKETCH_MAGIC) {
|
|
336
364
|
throw pikeletError(PIKELET_ERROR_CODES.SNAPSHOT_INVALID, 'Not a Pikelet sketch artifact (bad magic)');
|
|
@@ -353,7 +381,8 @@ class PikeletSketchArtifact {
|
|
|
353
381
|
const sketchesOffset = view.getUint32(40, true);
|
|
354
382
|
artifact.vectorsOffset = view.getUint32(44, true);
|
|
355
383
|
const fileBytes = Number(view.getBigUint64(48, true));
|
|
356
|
-
artifact.
|
|
384
|
+
artifact.declaredRecommendedRerank = view.getUint32(120, true);
|
|
385
|
+
artifact.recommendedRerank = Math.min(artifact.declaredRecommendedRerank, MAX_RECOMMENDED_RERANK);
|
|
357
386
|
// Retained so the lazy tier stays verifiable after open — see
|
|
358
387
|
// verifyVectors(). Copied out of the header read buffer.
|
|
359
388
|
artifact.vectorsSha256 = new Uint8Array(header.subarray(88, 120));
|
|
@@ -1131,6 +1160,7 @@ async function createSketchScanner(loadEngine, artifact, options = {}) {
|
|
|
1131
1160
|
|
|
1132
1161
|
module.exports = {
|
|
1133
1162
|
PikeletSketchArtifact,
|
|
1163
|
+
MAX_RECOMMENDED_RERANK,
|
|
1134
1164
|
createSketchScanner,
|
|
1135
1165
|
buildSketchArtifact,
|
|
1136
1166
|
buildSketchArtifactBytes,
|
|
@@ -105,5 +105,12 @@ export declare function exportSketchArtifact(
|
|
|
105
105
|
options?: SketchArtifactBuildOptions
|
|
106
106
|
): SketchArtifactBuildManifest;
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Ceiling on the header's recommendedRerank that readers use as their default
|
|
110
|
+
* rerank depth. Producers should not declare more: a reader will not honor it
|
|
111
|
+
* unless the caller passes an explicit rerank.
|
|
112
|
+
*/
|
|
113
|
+
export declare const MAX_RECOMMENDED_RERANK: number;
|
|
114
|
+
|
|
108
115
|
/** Parse and validate an untrusted uint8 engine snapshot (fails closed). */
|
|
109
116
|
export declare function parseUint8Snapshot(bytes: Uint8Array | ArrayBufferLike): Uint8SnapshotGraph;
|
|
@@ -12,13 +12,14 @@
|
|
|
12
12
|
const { NodeFileRangeSource, parseUint8Snapshot } = require('./pikelet-artifact-common.js');
|
|
13
13
|
const { PikeletRangeArtifact, buildRangeArtifact, buildRangeArtifactFile } = require('./pikelet-artifact-range.js');
|
|
14
14
|
const {
|
|
15
|
-
PikeletSketchArtifact, createSketchScanner,
|
|
15
|
+
PikeletSketchArtifact, MAX_RECOMMENDED_RERANK, createSketchScanner,
|
|
16
16
|
buildSketchArtifact, buildSketchArtifactBytes, buildSketchArtifactFile, exportSketchArtifact,
|
|
17
17
|
} = require('./pikelet-artifact-sketch.js');
|
|
18
18
|
|
|
19
19
|
module.exports = {
|
|
20
20
|
PikeletRangeArtifact,
|
|
21
21
|
PikeletSketchArtifact,
|
|
22
|
+
MAX_RECOMMENDED_RERANK,
|
|
22
23
|
createSketchScanner,
|
|
23
24
|
NodeFileRangeSource,
|
|
24
25
|
buildRangeArtifact,
|