diff --git a/examples/simple-go-ncruces/demo.go b/examples/simple-go-ncruces/demo.go index b0b29d3..b66da5b 100644 --- a/examples/simple-go-ncruces/demo.go +++ b/examples/simple-go-ncruces/demo.go @@ -4,7 +4,6 @@ import ( "bytes" _ "embed" "encoding/binary" - "fmt" "log" _ "github.com/asg017/sqlite-vec-ncruces-bindings" @@ -35,7 +34,7 @@ func main() { stmt.Step() - fmt.Printf("sqlite_version=%s, vec_version=%s\n", stmt.ColumnText(0), stmt.ColumnText(1)) + log.Printf("sqlite_version=%s, vec_version=%s\n", stmt.ColumnText(0), stmt.ColumnText(1)) err = db.Exec("CREATE VIRTUAL TABLE vec_items USING vec0(embedding float[4])") @@ -96,7 +95,7 @@ func main() { for stmt.Step() { rowid := stmt.ColumnInt64(0) distance := stmt.ColumnFloat(1) - fmt.Printf("rowid=%d, distance=%f\n", rowid, distance) + log.Printf("rowid=%d, distance=%f\n", rowid, distance) } if err := stmt.Err(); err != nil { log.Fatal(err) diff --git a/reference.yaml b/reference.yaml index 2e01867..face7f3 100644 --- a/reference.yaml +++ b/reference.yaml @@ -1,9 +1,19 @@ sections: - meta: Meta functions - constructor: Vector constructor functions - op: Vector operation functions - distance: Vector distance functions - quantize: Vector quantization functions + meta: + title: Meta + desc: TODO + constructors: + title: Constructors + desc: TODO + op: + title: Operations + desc: TODO + distance: + title: Distance functions + desc: TODO + quantization: + title: Quantization + desc: TODO functions: vec_version: params: [] @@ -15,34 +25,32 @@ functions: section: meta desc: Returns debugging information of the current `sqlite-vec` installation. example: select vec_debug(); - vec_bit: - params: [vector] - section: constructor - desc: Creates a binary vector from a BLOB. - example: - - select vec_bit(X'F0'); - - select subtype(vec_bit(X'F0')); - - select vec_to_json(vec_bit(X'F0')); vec_f32: params: [vector] - section: constructor + section: constructors desc: | Creates a float vector from a BLOB or JSON text. If a BLOB is provided, the length must be divisible by 4, as a float takes up 4 bytes of space each. + + The returned value is a BLOB with 4 bytes per element, with a special [subtype](https://www.sqlite.org/c3ref/result_subtype.html) + of `223`. example: - - select vec_float32('[.1, .2, .3, 4]'); - - select subtype(vec_float32('[.1, .2, .3, 4]')); - - select vec_float32(X'AABBCCDD'); - - select vec_to_json(vec_float32(X'AABBCCDD')); - - select vec_float32(X'AA'); + - select vec_f32('[.1, .2, .3, 4]'); + - select subtype(vec_f32('[.1, .2, .3, 4]')); + - select vec_f32(X'AABBCCDD'); + - select vec_to_json(vec_f32(X'AABBCCDD')); + - select vec_f32(X'AA'); vec_int8: params: [vector] - section: constructor - desc: | + section: constructors + desc: | Creates a 8-bit integer vector from a BLOB or JSON text. If a BLOB is provided, the length must be divisible by 4, as a float takes up 4 bytes of space each. If JSON text is provided, each element must be an integer between -128 and 127 inclusive. + The returned value is a BLOB with 1 byte per element, with a special [subtype](https://www.sqlite.org/c3ref/result_subtype.html) + of `225`. + example: - select vec_int8('[1, 2, 3, 4]'); - select subtype(vec_int8('[1, 2, 3, 4]')); @@ -50,14 +58,44 @@ functions: - select vec_to_json(vec_int8(X'AABBCCDD')); - select vec_int8('[999]'); + vec_bit: + params: [vector] + section: constructors + desc: | + Creates a binary vector from a BLOB. + + The returned value is a BLOB with 4 bytes per element, with a special [subtype](https://www.sqlite.org/c3ref/result_subtype.html) + of `224`. + example: + - select vec_bit(X'F0'); + - select subtype(vec_bit(X'F0')); + - select vec_to_json(vec_bit(X'F0')); + vec_length: + params: [vector] + section: op + desc: | + Returns the number of elements in the given vector. + The vector can be `JSON`, `BLOB`, or the result of a [constructor function](#constructors). + + This function will return an error if `vector` is invalid. + example: + - select vec_length('[.1, .2]'); + - select vec_length(X'AABBCCDD'); + - select vec_length(vec_int8(X'AABBCCDD')); + - select vec_length(vec_bit(X'AABBCCDD')); + - select vec_length(X'CCDD'); vec_add: params: [a, b] section: op desc: | - Adds each element in vector `a` with vector `b`, returning a new vector `c`. Both vectors - must be of the same type, and can only be a `float32` or `int8` vector. - example: | - - select vec_add( + Adds every element in vector `a` with vector `b`, returning a new vector `c`. Both vectors + must be of the same type and same length. Only `float32` and `int8` vectors are supported. + + An error is raised if either `a` or `b` are invalid, or if they are not the same type or same length. + + example: + - | + select vec_add( '[.1, .2, .3]', '[.4, .5, .6]' ); @@ -70,89 +108,101 @@ functions: ); - | select vec_to_json( - vec_int8('[1, 2, 3]'), - vec_int8('[4, 5, 6]') - ) - vec_length: - params: [] - section: op - desc: x - example: x - vec_normalize: - params: [] - section: op - desc: x - example: x - vec_slice: - params: [] - section: op - desc: x - example: x + vec_add( + vec_int8('[1, 2, 3]'), + vec_int8('[4, 5, 6]') + ) + ); + - select vec_add('[.1]', vec_int8('[1]')); + - select vec_add(vec_bit(X'AA'), vec_bit(X'BB')); vec_sub: - params: [] + params: [a, b] section: op desc: x - example: x + example: + - | + select vec_sub( + '[.1, .2, .3]', + '[.4, .5, .6]' + ); + - | + select vec_to_json( + vec_sub( + '[.1, .2, .3]', + '[.4, .5, .6]' + ) + ); + - | + select vec_to_json( + vec_sub( + vec_int8('[1, 2, 3]'), + vec_int8('[4, 5, 6]') + ) + ); + - select vec_sub('[.1]', vec_int8('[1]')); + - select vec_sub(vec_bit(X'AA'), vec_bit(X'BB')); + vec_normalize: + params: [vector] + section: op + desc: x + example: select 'todo'; + vec_slice: + params: [vector, start, end] + section: op + desc: x + example: select 'todo'; vec_to_json: - params: [] + params: [vector] section: op desc: x - example: x + example: select 'todo'; vec_distance_cosine: - params: [] + params: [a, b] section: distance desc: x - example: x + example: select 'todo'; vec_distance_hamming: - params: [] + params: [a, b] section: distance desc: x - example: x + example: select 'todo'; vec_distance_l2: - params: [] + params: [a, b] section: distance desc: x - example: x + example: select 'todo'; vec_quantize_binary: - params: [] + params: [vector] section: quantization desc: x - example: x + example: select 'todo'; vec_quantize_i8: - params: [] + params: [vector, "[start]", "[end]"] section: quantization desc: x - example: x - vec_quantize_i8: - params: [] - section: quantization - desc: x - example: x - -table_functions: - vec_each: - columns: [rowid, value] - inputs: ["vector"] - desc: - example: - vec_npy_each: - columns: [rowid, vector] - inputs: ["input"] - desc: - example: - -virtual_tables: - vec0: - desc: - example: - -entrypoints: - sqlite3_vec_init: {} - sqlite3_vec_fs_read_init: {} -compile_options: - - SQLITE_VEC_ENABLE_AVX - - SQLITE_VEC_ENABLE_NEON - - SQLITE_VEC_OMIT_FS - + example: select 'todo'; +#table_functions: +# vec_each: +# columns: [rowid, value] +# inputs: ["vector"] +# desc: +# example: +# vec_npy_each: +# columns: [rowid, vector] +# inputs: ["input"] +# desc: +# example: +#virtual_tables: +# vec0: +# desc: +# example: +#entrypoints: +# sqlite3_vec_init: {} +# sqlite3_vec_fs_read_init: {} +#compile_options: +# - SQLITE_VEC_ENABLE_AVX +# - SQLITE_VEC_ENABLE_NEON +# - SQLITE_VEC_OMIT_FS +# diff --git a/site/api-reference.md b/site/api-reference.md index e69de29..aa92ca2 100644 --- a/site/api-reference.md +++ b/site/api-reference.md @@ -0,0 +1,324 @@ +# API Reference + +::: warning +sqlite-vec is pre-v1, so expect breaking changes. +::: + +[[toc]] + +## Meta {#meta} + +TODO + +### `vec_version()` {#vec_version} + +Returns a version string of the current `sqlite-vec` installation. + +```sql +select vec_version(); +-- 'v0.0.1-alpha.33' + + +``` + +### `vec_debug()` {#vec_debug} + +Returns debugging information of the current `sqlite-vec` installation. + +```sql +select vec_debug(); +/* +'Version: v0.0.1-alpha.33 +Date: 2024-07-14T14:24:27Z-0700 +Commit: 18e33edf143cafd881643965a559cd0259ab0666 +Build flags: avx ' +*/ + + +``` + +## Constructors {#constructors} + +TODO + +### `vec_f32(vector)` {#vec_f32} + +Creates a float vector from a BLOB or JSON text. If a BLOB is provided, +the length must be divisible by 4, as a float takes up 4 bytes of space each. + +The returned value is a BLOB with 4 bytes per element, with a special [subtype](https://www.sqlite.org/c3ref/result_subtype.html) +of `223`. + + +```sql +select vec_f32('[.1, .2, .3, 4]'); +-- X'CDCCCC3DCDCC4C3E9A99993E008040' + +select subtype(vec_f32('[.1, .2, .3, 4]')); +-- 223 + +select vec_f32(X'AABBCCDD'); +-- X'AABBCCDD' + +select vec_to_json(vec_f32(X'AABBCCDD')); +-- '[-1844071490169864000.000000]' + +select vec_f32(X'AA'); +-- ❌ invalid float32 vector BLOB length. Must be divisible by 4, found 1 + + +``` + +### `vec_int8(vector)` {#vec_int8} + +Creates a 8-bit integer vector from a BLOB or JSON text. If a BLOB is provided, +the length must be divisible by 4, as a float takes up 4 bytes of space each. +If JSON text is provided, each element must be an integer between -128 and 127 inclusive. + +The returned value is a BLOB with 1 byte per element, with a special [subtype](https://www.sqlite.org/c3ref/result_subtype.html) +of `225`. + + +```sql +select vec_int8('[1, 2, 3, 4]'); +-- X'1234' + +select subtype(vec_int8('[1, 2, 3, 4]')); +-- 225 + +select vec_int8(X'AABBCCDD'); +-- X'AABBCCDD' + +select vec_to_json(vec_int8(X'AABBCCDD')); +-- '[-86,-69,-52,-35]' + +select vec_int8('[999]'); +-- ❌ JSON parsing error: value out of range for int8 + + +``` + +### `vec_bit(vector)` {#vec_bit} + +Creates a binary vector from a BLOB. + +The returned value is a BLOB with 4 bytes per element, with a special [subtype](https://www.sqlite.org/c3ref/result_subtype.html) +of `224`. + + +```sql +select vec_bit(X'F0'); +-- X'F0' + +select subtype(vec_bit(X'F0')); +-- 224 + +select vec_to_json(vec_bit(X'F0')); +-- '[0,0,0,0,1,1,1,1]' + + +``` + +## Operations {#op} + +TODO + +### `vec_length(vector)` {#vec_length} + +Returns the number of elements in the given vector. +The vector can be `JSON`, `BLOB`, or the result of a [constructor function](#constructors). + +This function will return an error if `vector` is invalid. + + +```sql +select vec_length('[.1, .2]'); +-- 2 + +select vec_length(X'AABBCCDD'); +-- 1 + +select vec_length(vec_int8(X'AABBCCDD')); +-- 4 + +select vec_length(vec_bit(X'AABBCCDD')); +-- 32 + +select vec_length(X'CCDD'); +-- ❌ invalid float32 vector BLOB length. Must be divisible by 4, found 2 + + +``` + +### `vec_add(a, b)` {#vec_add} + +Adds every element in vector `a` with vector `b`, returning a new vector `c`. Both vectors +must be of the same type and same length. Only `float32` and `int8` vectors are supported. + +An error is raised if either `a` or `b` are invalid, or if they are not the same type or same length. + + +```sql +select vec_add( + '[.1, .2, .3]', + '[.4, .5, .6]' +); +-- X'0003F3333333F6766663F' + +select vec_to_json( + vec_add( + '[.1, .2, .3]', + '[.4, .5, .6]' + ) +); +-- '[0.500000,0.700000,0.900000]' + +select vec_to_json( + vec_add( + vec_int8('[1, 2, 3]'), + vec_int8('[4, 5, 6]') + ) +); +-- '[5,7,9]' + +select vec_add('[.1]', vec_int8('[1]')); +-- ❌ Vector type mistmatch. First vector has type float32, while the second has type int8. + +select vec_add(vec_bit(X'AA'), vec_bit(X'BB')); +-- ❌ Cannot add two bitvectors together. + + +``` + +### `vec_sub(a, b)` {#vec_sub} + +x + +```sql +select vec_sub( + '[.1, .2, .3]', + '[.4, .5, .6]' +); +-- X'9A9999BE9A9999BE9A9999BE' + +select vec_to_json( + vec_sub( + '[.1, .2, .3]', + '[.4, .5, .6]' + ) +); +-- '[-0.300000,-0.300000,-0.300000]' + +select vec_to_json( + vec_sub( + vec_int8('[1, 2, 3]'), + vec_int8('[4, 5, 6]') + ) +); +-- '[-3,-3,-3]' + +select vec_sub('[.1]', vec_int8('[1]')); +-- ❌ Vector type mistmatch. First vector has type float32, while the second has type int8. + +select vec_sub(vec_bit(X'AA'), vec_bit(X'BB')); +-- ❌ Cannot subtract two bitvectors together. + + +``` + +### `vec_normalize(vector)` {#vec_normalize} + +x + +```sql +select 'todo'; +-- 'todo' + + +``` + +### `vec_slice(vector, start, end)` {#vec_slice} + +x + +```sql +select 'todo'; +-- 'todo' + + +``` + +### `vec_to_json(vector)` {#vec_to_json} + +x + +```sql +select 'todo'; +-- 'todo' + + +``` + +## Distance functions {#distance} + +TODO + +### `vec_distance_cosine(a, b)` {#vec_distance_cosine} + +x + +```sql +select 'todo'; +-- 'todo' + + +``` + +### `vec_distance_hamming(a, b)` {#vec_distance_hamming} + +x + +```sql +select 'todo'; +-- 'todo' + + +``` + +### `vec_distance_l2(a, b)` {#vec_distance_l2} + +x + +```sql +select 'todo'; +-- 'todo' + + +``` + +## Quantization {#quantization} + +TODO + +### `vec_quantize_binary(vector)` {#vec_quantize_binary} + +x + +```sql +select 'todo'; +-- 'todo' + + +``` + +### `vec_quantize_i8(vector, [start], [end])` {#vec_quantize_i8} + +x + +```sql +select 'todo'; +-- 'todo' + + +``` + diff --git a/site/build-ref.mjs b/site/build-ref.mjs new file mode 100644 index 0000000..76a0704 --- /dev/null +++ b/site/build-ref.mjs @@ -0,0 +1,194 @@ +import Database from "better-sqlite3"; +import { load } from "js-yaml"; +import { fileURLToPath } from "node:url"; +import { resolve, dirname } from "node:path"; +import { readFileSync, writeFileSync } from "node:fs"; +import * as v from "valibot"; +import { table } from "table"; + +const REF_PATH = resolve( + dirname(fileURLToPath(import.meta.url)), + "../reference.yaml" +); +const EXT_PATH = resolve( + dirname(fileURLToPath(import.meta.url)), + "../dist/vec0" +); + +const DocSchema = v.object({ + sections: v.record( + v.string(), + v.object({ + title: v.string(), + desc: v.string(), + }) + ), + functions: v.record( + v.string(), + v.object({ + params: v.array(v.string()), + desc: v.string(), + section: v.string(), + example: v.union([v.string(), v.array(v.string())]), + }) + ), + /*table_functions: v.record( + v.string(), + v.object({ + params: v.array(v.string()), + desc: v.string(), + example: v.union([v.string(), v.array(v.string())]), + }) + ),*/ +}); + +const tableConfig = { + border: { + topBody: `─`, + topJoin: `┬`, + topLeft: `┌`, + topRight: `┐`, + + bottomBody: `─`, + bottomJoin: `┴`, + bottomLeft: `└`, + bottomRight: `┘`, + + bodyLeft: `│`, + bodyRight: `│`, + bodyJoin: `│`, + + joinBody: `─`, + joinLeft: `├`, + joinRight: `┤`, + joinJoin: `┼`, + }, +}; + +function formatSingleValue(value) { + if (typeof value === "string") { + const s = `'${value.replace(/'/g, "''")}'`; + if (s.split("\n").length > 1) { + return `/*\n${s}\n*/`; + } + return `-- ${s}`; + } + if (typeof value === "number") return `-- ${value.toString()}`; + if (value === null) return "-- NULL"; + if (value instanceof Uint8Array) { + let s = "X'"; + for (const v of value) { + s += v.toString(16).toUpperCase(); + } + s += "'"; + return `-- ${s}`; + } + if (typeof value === "object" || Array.isArray(value)) + return "-- " + JSON.stringify(value, null, 2); +} +function formatValue(value) { + if (typeof value === "string" || typeof value === "number") return value; + if (value === null) return "NULL"; + if (value instanceof Uint8Array) { + let s = "X'"; + for (const v of value) { + s += v.toString(16); + } + s += "'"; + return s; + } + if (typeof value === "object" || Array.isArray(value)) + return JSON.stringify(value, null, 2); +} +function tableize(stmt, results) { + const columnNames = stmt.columns().map((c) => c.name); + const rows = results.map((row) => + row.map((value) => { + return formatValue(value); + }) + ); + return table([columnNames, ...rows], tableConfig); +} + +function renderExamples(db, name, example) { + let md = "```sql\n"; + + const examples = Array.isArray(example) ? example : [example]; + for (const example of examples) { + const sql = example + /* Strip any '```sql' markdown at the beginning */ + .replace(/^\w*```sql/, "") + /* Strip any '```' markdown at the end */ + .replace(/```\w*$/m, "") + .trim(); + let stmt, results, error; + results = null; + try { + stmt = db.prepare(sql); + stmt.raw(true); + } catch (error) { + console.error(`Error preparing statement for ${name}:`); + console.error(error); + throw Error(); + } + + try { + results = stmt.all(); + } catch (e) { + error = e.message; + } + + md += sql + "\n"; + + if (!results) { + md += `-- ❌ ${error}\n\n`; + continue; + } + + const result = + results.length > 1 || stmt.columns().length > 1 + ? `/*\n${tableize(stmt, results)}\n*/\n` + : formatSingleValue(results[0][0]); + md += result + "\n\n"; + } + + md += "\n```\n\n"; + + return md; +} + +let md = `# API Reference + +::: warning +sqlite-vec is pre-v1, so expect breaking changes. +::: + +[[toc]] + +`; +const doc = v.parse(DocSchema, load(readFileSync(REF_PATH, "utf8"))); + +const db = new Database(); +db.loadExtension(EXT_PATH); + +let lastSection = null; +for (const [name, { params, desc, example, section }] of Object.entries( + doc.functions +)) { + const headerText = `\`${name}(${(params ?? []).join(", ")})\` {#${name}}`; + + if (lastSection != section) { + md += `## ${doc.sections[section].title} {#${section}} \n\n`; + md += doc.sections[section].desc; + md += "\n\n"; + lastSection = section; + } + + md += "### " + headerText + "\n\n"; + + md += desc + "\n\n"; + md += renderExamples(db, name, example); +} + +writeFileSync("api-reference.md", md, "utf8"); +console.log("done"); diff --git a/site/package-lock.json b/site/package-lock.json index e971ef5..168ea50 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -6,6 +6,10 @@ "": { "dependencies": { "@types/node": "^20.12.8", + "better-sqlite3": "^11.1.2", + "js-yaml": "^4.1.0", + "table": "^6.8.2", + "valibot": "^0.36.0", "vitepress": "^1.1.4" }, "devDependencies": { @@ -1140,6 +1144,21 @@ } } }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/algoliasearch": { "version": "4.23.3", "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.23.3.tgz", @@ -1162,11 +1181,180 @@ "@algolia/transporter": "4.23.3" } }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/better-sqlite3": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.1.2.tgz", + "integrity": "sha512-gujtFwavWU4MSPT+h9B+4pkvZdyOUkH54zgLdIrMmmmd4ZqiBIrRNBzNzYVFO417xo882uP5HBu4GjOfaSrIQw==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "prebuild-install": "^7.1.1" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -1220,6 +1408,29 @@ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/focus-trap": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", @@ -1228,6 +1439,11 @@ "tabbable": "^6.2.0" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1241,11 +1457,74 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, "node_modules/hookable": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==" }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" + }, "node_modules/magic-string": { "version": "0.30.10", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", @@ -1259,6 +1538,25 @@ "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==" }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minisearch": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-6.3.0.tgz", @@ -1269,6 +1567,11 @@ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -1286,6 +1589,30 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node_modules/node-abi": { + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", + "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/perfect-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", @@ -1332,6 +1659,75 @@ "url": "https://opencollective.com/preact" } }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/rfdc": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", @@ -1371,12 +1767,42 @@ "fsevents": "~2.3.2" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/search-insights": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.13.0.tgz", "integrity": "sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw==", "peer": true }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/shiki": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.4.0.tgz", @@ -1385,6 +1811,65 @@ "@shikijs/core": "1.4.0" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, "node_modules/source-map-js": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", @@ -1401,16 +1886,118 @@ "node": ">=0.10.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tabbable": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" }, + "node_modules/table": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", + "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/valibot": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.36.0.tgz", + "integrity": "sha512-CjF1XN4sUce8sBK9TixrDqFM7RwNkuXdJu174/AwmQUB62QbCQADg5lLe8ldBalFgtj1uKj+pKwDJiNo4Mn+eQ==" + }, "node_modules/vite": { "version": "5.2.11", "resolved": "https://registry.npmjs.org/vite/-/vite-5.2.11.tgz", @@ -1521,6 +2108,11 @@ "optional": true } } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" } } } diff --git a/site/package.json b/site/package.json index 0fcd50a..a2bef17 100644 --- a/site/package.json +++ b/site/package.json @@ -1,7 +1,8 @@ { "scripts": { + "ref": "node build-ref.mjs", "dev": "vitepress dev", - "build": "vitepress build", + "build": "npm run ref && vitepress build", "preview": "vitepress preview" }, "devDependencies": { @@ -9,6 +10,10 @@ }, "dependencies": { "@types/node": "^20.12.8", + "better-sqlite3": "^11.1.2", + "js-yaml": "^4.1.0", + "table": "^6.8.2", + "valibot": "^0.36.0", "vitepress": "^1.1.4" } } diff --git a/sqlite-vec.c b/sqlite-vec.c index 7aa3b64..9b02872 100644 --- a/sqlite-vec.c +++ b/sqlite-vec.c @@ -523,6 +523,10 @@ static int fvec_from_value(sqlite3_value *value, f32 **vector, if (value_type == SQLITE_TEXT) { const char *source = (const char *)sqlite3_value_text(value); int source_len = sqlite3_value_bytes(value); + if(source_len == 0) { + *pzErr = sqlite3_mprintf("zero-length vectors are not supported."); + return SQLITE_ERROR; + } int i = 0; struct Array x; @@ -658,6 +662,11 @@ static int int8_vec_from_value(sqlite3_value *value, i8 **vector, int source_len = sqlite3_value_bytes(value); int i = 0; + if(source_len == 0) { + *pzErr = sqlite3_mprintf("zero-length vectors are not supported."); + return SQLITE_ERROR; + } + struct Array x; int rc = array_init(&x, sizeof(i8), ceil(source_len / 2.0)); if (rc != SQLITE_OK) { @@ -805,7 +814,7 @@ int ensure_vector_match(sqlite3_value *aValue, sqlite3_value *bValue, void **a, int rc; enum VectorElementType aType, bType; size_t aDims, bDims; - char *error; + char *error = NULL; vector_cleanup aCleanup, bCleanup; rc = vector_from_value(aValue, a, &aDims, &aType, &aCleanup, &error); @@ -828,8 +837,8 @@ int ensure_vector_match(sqlite3_value *aValue, sqlite3_value *bValue, void **a, sqlite3_mprintf("Vector type mistmatch. First vector has type %s, " "while the second has type %s.", vector_subtype_name(aType), vector_subtype_name(bType)); - aCleanup(a); - bCleanup(b); + aCleanup(*a); + bCleanup(*b); return SQLITE_ERROR; } if (aDims != bDims) { @@ -837,8 +846,8 @@ int ensure_vector_match(sqlite3_value *aValue, sqlite3_value *bValue, void **a, "Vector dimension mistmatch. First vector has %ld dimensions, " "while the second has %ld dimensions.", aDims, bDims); - aCleanup(a); - bCleanup(b); + aCleanup(*a); + bCleanup(*b); return SQLITE_ERROR; } *element_type = aType; @@ -879,7 +888,7 @@ static void vec_npy_file(sqlite3_context *context, int argc, static void vec_f32(sqlite3_context *context, int argc, sqlite3_value **argv) { assert(argc == 1); int rc; - f32 *vector; + f32 *vector = NULL; size_t dimensions; fvec_cleanup cleanup; char *errmsg; @@ -953,7 +962,7 @@ static void vec_distance_cosine(sqlite3_context *context, int argc, sqlite3_value **argv) { assert(argc == 2); int rc; - void *a, *b; + void *a = NULL, *b = NULL; size_t dimensions; vector_cleanup aCleanup, bCleanup; char *error; @@ -995,7 +1004,7 @@ static void vec_distance_l2(sqlite3_context *context, int argc, sqlite3_value **argv) { assert(argc == 2); int rc; - void *a, *b; + void *a = NULL, *b = NULL; size_t dimensions; vector_cleanup aCleanup, bCleanup; char *error; @@ -1035,7 +1044,7 @@ static void vec_distance_hamming(sqlite3_context *context, int argc, sqlite3_value **argv) { assert(argc == 2); int rc; - void *a, *b; + void *a = NULL, *b = NULL; size_t dimensions; vector_cleanup aCleanup, bCleanup; char *error; @@ -1187,7 +1196,7 @@ static void vec_quantize_binary(sqlite3_context *context, int argc, static void vec_add(sqlite3_context *context, int argc, sqlite3_value **argv) { assert(argc == 2); int rc; - void *a, *b; + void *a = NULL, *b = NULL; size_t dimensions; vector_cleanup aCleanup, bCleanup; char *error; @@ -1244,7 +1253,7 @@ finish: static void vec_sub(sqlite3_context *context, int argc, sqlite3_value **argv) { assert(argc == 2); int rc; - void *a, *b; + void *a = NULL, *b = NULL; size_t dimensions; vector_cleanup aCleanup, bCleanup; char *error; diff --git a/tests/fuzz.py b/tests/fuzz.py new file mode 100644 index 0000000..10a4083 --- /dev/null +++ b/tests/fuzz.py @@ -0,0 +1,36 @@ +import sqlite3 +EXT_PATH = "dist/vec0" +db = sqlite3.connect(":memory:") + +db.execute( + "create temp table base_functions as select name from pragma_function_list" +) +db.execute("create temp table base_modules as select name from pragma_module_list") + +db.enable_load_extension(True) +db.load_extension(EXT_PATH) +db.row_factory = sqlite3.Row +loaded_functions = db.execute( + "select name, narg from pragma_function_list where name not in (select name from base_functions) order by name" +).fetchall() + +db.execute( + "create temp table loaded_modules as select name from pragma_module_list where name not in (select name from base_modules) order by name" +) + +db.row_factory = sqlite3.Row + +def trace(sql): + print(sql) +db.set_trace_callback(trace) + +def spread_args(n): + return ",".join(["?"] * n) + +for f in loaded_functions: + v = [None, 1, 1.2, b"", '', "asdf", b"\xff", b"\x00", "\0\0\0\0"] + for x in v: + try: + db.execute("select {}({}); ".format(f['name'],spread_args(f['narg'])), [x] * f['narg']) + except sqlite3.OperationalError: + pass