From 653da6cca7325267fa9d815a338b56e43da879e4 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 30 Jun 2022 12:22:02 -0600 Subject: [PATCH 01/28] Vector Similarity field definition & builder --- lib/entity/entity-value.ts | 2 +- lib/entity/entity.ts | 4 +- lib/entity/fields/entity-vector-field.ts | 6 + lib/entity/fields/index.ts | 3 +- lib/schema/builders/hash-schema-builder.ts | 5 + lib/schema/builders/json-schema-builder.ts | 5 + lib/schema/builders/schema-builder.ts | 45 ++++++ lib/schema/definition/field-definition.ts | 3 +- lib/schema/definition/index.ts | 1 + lib/schema/definition/schema-field-type.ts | 2 +- .../definition/vector-field-definition.ts | 52 +++++++ lib/schema/schema.ts | 2 +- spec/unit/schema/vector-hash-fields.spec.ts | 138 +++++++++++++++++ spec/unit/schema/vector-json-fields.spec.ts | 139 ++++++++++++++++++ 14 files changed, 401 insertions(+), 6 deletions(-) create mode 100644 lib/entity/fields/entity-vector-field.ts create mode 100644 lib/schema/definition/vector-field-definition.ts create mode 100644 spec/unit/schema/vector-hash-fields.spec.ts create mode 100644 spec/unit/schema/vector-json-fields.spec.ts diff --git a/lib/entity/entity-value.ts b/lib/entity/entity-value.ts index 92dcfa71..86bc9f01 100644 --- a/lib/entity/entity-value.ts +++ b/lib/entity/entity-value.ts @@ -3,4 +3,4 @@ import { Point } from "./point"; /** * Valid types for properties on an {@link Entity}. */ -export type EntityValue = string | number | boolean | Point | Date | any[] | null; +export type EntityValue = string | number | boolean | Point | Date | any[] | ArrayBuffer | null; diff --git a/lib/entity/entity.ts b/lib/entity/entity.ts index eff16339..d31b71c6 100644 --- a/lib/entity/entity.ts +++ b/lib/entity/entity.ts @@ -8,6 +8,7 @@ import { EntityStringArrayField, EntityStringField, EntityTextField, + EntityVectorField, EntityFieldConstructor, } from "./fields"; import { Schema } from "../schema/schema"; @@ -21,7 +22,8 @@ const ENTITY_FIELD_CONSTRUCTORS: Record 'text': EntityTextField, 'date': EntityDateField, 'point': EntityPointField, - 'string[]': EntityStringArrayField + 'string[]': EntityStringArrayField, + 'vector': EntityVectorField, } /** diff --git a/lib/entity/fields/entity-vector-field.ts b/lib/entity/fields/entity-vector-field.ts new file mode 100644 index 00000000..bd11ac49 --- /dev/null +++ b/lib/entity/fields/entity-vector-field.ts @@ -0,0 +1,6 @@ +import { EntityField } from "./entity-field"; +import { EntityValue } from "../entity-value"; + +export class EntityVectorField extends EntityField { + // TODO: implement! +} diff --git a/lib/entity/fields/index.ts b/lib/entity/fields/index.ts index 7d112f05..021ca2e8 100644 --- a/lib/entity/fields/index.ts +++ b/lib/entity/fields/index.ts @@ -7,4 +7,5 @@ export * from './entity-point-field' export * from './entity-string-array-field' export * from './entity-string-field' export * from './entity-stringish-field' -export * from './entity-text-field' \ No newline at end of file +export * from './entity-text-field' +export * from './entity-vector-field' \ No newline at end of file diff --git a/lib/schema/builders/hash-schema-builder.ts b/lib/schema/builders/hash-schema-builder.ts index 5a2091a0..86384e77 100644 --- a/lib/schema/builders/hash-schema-builder.ts +++ b/lib/schema/builders/hash-schema-builder.ts @@ -52,6 +52,11 @@ export class HashSchemaBuilder extends SchemaBuilder extends SchemaBuilder { protected buildWeight(field: WeightFieldDefinition) { return field.weight ? ['WEIGHT', field.weight.toString()] : [] } + + protected buildVector(field: VectorFieldDefinition) { + // assume that indexed: false takes precedence + if (!(field.indexed ?? this.schema.indexedDefault)) { + return ['NOINDEX'] + } + + const results = [ + 'TYPE', field.vector.vector_type ?? 'FLOAT32', + 'DIM', field.vector.dim.toString(), + 'DISTANCE_METRIC', field.vector.distance_metric, + ] + + if (field.vector.initial_cap) { + results.push('INITIAL_CAP', field.vector.initial_cap.toString()) + } + + switch (field.vector.algorithm) { + case 'FLAT': + if (field.vector.block_size) { + results.push('BLOCK_SIZE', field.vector.block_size.toString()) + } + break + + case 'HNSW': + if (field.vector.m) { + results.push('M', field.vector.m.toString()) + } + if (field.vector.ef_construction) { + results.push('EF_CONSTRUCTION', field.vector.ef_construction.toString()) + } + if (field.vector.ef_runtime) { + results.push('EF_RUNTIME', field.vector.ef_runtime.toString()) + } + break + } + + return [ + 'VECTOR', + field.vector.algorithm, + results.length.toString(), + ...results, + ] + } } diff --git a/lib/schema/definition/field-definition.ts b/lib/schema/definition/field-definition.ts index bf380da1..abbf475d 100644 --- a/lib/schema/definition/field-definition.ts +++ b/lib/schema/definition/field-definition.ts @@ -5,6 +5,7 @@ import { PointFieldDefinition } from "./point-field-definition"; import { StringArrayFieldDefinition } from "./string-array-field-definition"; import { StringFieldDefinition } from "./string-field-definition"; import { TextFieldDefinition } from "./text-field-definition"; +import { VectorFieldDefinition } from "./vector-field-definition"; /** Contains instructions telling how to map a property on an {@link Entity} to Redis. */ -export type FieldDefinition = StringFieldDefinition | TextFieldDefinition | NumberFieldDefinition | BooleanFieldDefinition | PointFieldDefinition | DateFieldDefinition | StringArrayFieldDefinition; +export type FieldDefinition = StringFieldDefinition | TextFieldDefinition | NumberFieldDefinition | BooleanFieldDefinition | PointFieldDefinition | DateFieldDefinition | StringArrayFieldDefinition | VectorFieldDefinition; diff --git a/lib/schema/definition/index.ts b/lib/schema/definition/index.ts index df6a56ed..0abdfc9e 100644 --- a/lib/schema/definition/index.ts +++ b/lib/schema/definition/index.ts @@ -15,4 +15,5 @@ export * from './stemming-field-definition' export * from './string-array-field-definition' export * from './string-field-definition' export * from './text-field-definition' +export * from './vector-field-definition' export * from './weight-field-definition' \ No newline at end of file diff --git a/lib/schema/definition/schema-field-type.ts b/lib/schema/definition/schema-field-type.ts index c13909a1..5b695b80 100644 --- a/lib/schema/definition/schema-field-type.ts +++ b/lib/schema/definition/schema-field-type.ts @@ -1,4 +1,4 @@ /** * Valid types a {@link FieldDefinition}. */ -export type SchemaFieldType = 'string' | 'number' | 'boolean' | 'text' | 'date' | 'point' | 'string[]'; +export type SchemaFieldType = 'string' | 'number' | 'boolean' | 'text' | 'date' | 'point' | 'string[]' | 'vector'; diff --git a/lib/schema/definition/vector-field-definition.ts b/lib/schema/definition/vector-field-definition.ts new file mode 100644 index 00000000..a9b1b061 --- /dev/null +++ b/lib/schema/definition/vector-field-definition.ts @@ -0,0 +1,52 @@ +import { BaseFieldDefinition } from "./base-field-definition"; + +type Algorithm = 'FLAT' | 'HNSW' + +interface VectorParameters { + // vector algorithm to use + algorithm: Algorithm, + + // vector type, currently only FLOAT32 supported + vector_type?: 'FLOAT32', + + // vector dimension + dim: number, + + // Supported distance metric + distance_metric: 'L2' | 'IP' | 'COSINE', + + // Initial vector capacity in the index affecting memory allocation size of the index + initial_cap?: number, +} + +interface FlatVectorParameters extends VectorParameters { + algorithm: 'FLAT', + + // Block size to hold amount of vectors in a contiguous array + block_size?: number, // default 1,048,576 (1024*1024) +} + +interface HNSWVectorParameters extends VectorParameters { + algorithm: 'HNSW'; + + // Number of maximum allowed outgoing edges for each node in the graph in each layer + m?: number, + + // Number of maximum allowed potential outgoing edges candidates for each node in the + // graph, during the graph building + ef_construction?: number + + // Number of maximum top candidates to hold during the KNN search + ef_runtime?: number, // 10 +} + +type VectorAlgorithm = FlatVectorParameters | HNSWVectorParameters + +/** A field representing vector similarity. */ +export interface VectorFieldDefinition extends BaseFieldDefinition { + /** Yep. It's a vector. */ + type: 'vector'; + + // vector parameters + vector: VectorAlgorithm; +} diff --git a/lib/schema/schema.ts b/lib/schema/schema.ts index bcc6716e..ada703cd 100644 --- a/lib/schema/schema.ts +++ b/lib/schema/schema.ts @@ -163,7 +163,7 @@ export class Schema { } private validateFieldDef(field: string, fieldDef: FieldDefinition) { - if (!['boolean', 'date', 'number', 'point', 'string', 'string[]', 'text'].includes(fieldDef.type)) + if (!['boolean', 'date', 'number', 'point', 'string', 'string[]', 'text', 'vector'].includes(fieldDef.type)) throw Error(`The field '${field}' is configured with a type of '${fieldDef.type}'. Valid types include 'boolean', 'date', 'number', 'point', 'string', 'string[]', and 'text'.`); } } diff --git a/spec/unit/schema/vector-hash-fields.spec.ts b/spec/unit/schema/vector-hash-fields.spec.ts new file mode 100644 index 00000000..ad215df4 --- /dev/null +++ b/spec/unit/schema/vector-hash-fields.spec.ts @@ -0,0 +1,138 @@ +import { Schema } from '$lib/schema/schema'; +import { Entity } from '$lib/entity/entity'; +import { SchemaDefinition } from '$lib/schema/definition'; +import { DataStructure } from '$lib/schema/options'; + +describe("Schema", () => { + describe.each([ + + ["that defines a FLAT / 512 / COSINE vector for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + ["that defines a FLAT / 256 / IP vector for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' + ] + }], + + ["that defines a FLAT / 1024 / L2 vector for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' + ] + }], + + ["that defines a FLAT / 512 / COSINE vector with block_size for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', block_size: 512*512 } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'FLAT', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'BLOCK_SIZE', '262144' + ] + }], + + ["that defines an aliased FLAT / 512 / COSINE vector for a HASH", { + schemaDef: { aField: { type: 'vector', alias: 'anotherField', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'anotherField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing + // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence + ["that defines an unindexed FLAT vector for a HASH", { + schemaDef: { aField: { type: 'vector', indexed: false, vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'NOINDEX' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + ["that defines a HNSW / 256 / IP vector for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' + ] + }], + + ["that defines a HNSW / 1024 / L2 vector for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with M for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', m: 8 } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'M', '8' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with EF_CONSTRUCTION for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_construction: 250 } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_CONSTRUCTION', '250' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with EF_RUNTIME for a HASH", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_runtime: 20 } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_RUNTIME', '20' + ] + }], + + ["that defines an aliased HNSW / 512 / COSINE vector for a HASH", { + schemaDef: { aField: { type: 'vector', alias: 'anotherField', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'anotherField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing + // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence + ["that defines an unindexed HNSW vector for a HASH", { + schemaDef: { aField: { type: 'vector', indexed: false, vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'NOINDEX' + ] + }], + + ])("%s", (_, data) => { + + class TestEntity extends Entity {} + + it("generates a Redis schema for the field", () => { + let schemaDef = data.schemaDef; + let dataStructure = data.dataStructure as DataStructure; + let expectedRedisSchema = data.expectedRedisSchema; + + let schema = new Schema(TestEntity, schemaDef, { dataStructure }); + expect(schema.redisSchema).toEqual(expectedRedisSchema); + }); + }); +}); diff --git a/spec/unit/schema/vector-json-fields.spec.ts b/spec/unit/schema/vector-json-fields.spec.ts new file mode 100644 index 00000000..da3a2b92 --- /dev/null +++ b/spec/unit/schema/vector-json-fields.spec.ts @@ -0,0 +1,139 @@ +import { Schema } from '$lib/schema/schema'; +import { Entity } from '$lib/entity/entity'; +import { SchemaDefinition } from '$lib/schema/definition'; +import { DataStructure } from '$lib/schema/options'; + +describe("Schema", () => { + describe.each([ + + ["that defines a FLAT / 512 / COSINE vector for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + ["that defines a FLAT / 256 / IP vector for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' + ] + }], + + ["that defines a FLAT / 1024 / L2 vector for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' + ] + }], + + ["that defines a FLAT / 512 / COSINE vector with block_size for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', block_size: 512*512 } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'BLOCK_SIZE', '262144' + ] + }], + + ["that defines an aliased FLAT / 512 / COSINE vector for a JSON", { + schemaDef: { aField: { type: 'vector', alias: 'anotherField', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.anotherField', 'AS', 'anotherField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing + // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence + ["that defines an unindexed FLAT vector for a JSON", { + schemaDef: { aField: { type: 'vector', indexed: false, vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'NOINDEX' + ] + }], + + + ["that defines a HNSW / 512 / COSINE vector for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + ["that defines a HNSW / 256 / IP vector for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' + ] + }], + + ["that defines a HNSW / 1024 / L2 vector for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with M for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', m: 8 } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'M', '8' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with EF_CONSTRUCTION for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_construction: 250 } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_CONSTRUCTION', '250' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with EF_RUNTIME for a JSON", { + schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_runtime: 20 } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_RUNTIME', '20' + ] + }], + + ["that defines an aliased HNSW / 512 / COSINE vector for a JSON", { + schemaDef: { aField: { type: 'vector', alias: 'anotherField', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.anotherField', 'AS', 'anotherField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing + // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence + ["that defines an unindexed HNSW vector for a JSON", { + schemaDef: { aField: { type: 'vector', indexed: false, vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'NOINDEX' + ] + }], + + ])("%s", (_, data) => { + + class TestEntity extends Entity {} + + it("generates a Redis schema for the field", () => { + let schemaDef = data.schemaDef; + let dataStructure = data.dataStructure as DataStructure; + let expectedRedisSchema = data.expectedRedisSchema; + + let schema = new Schema(TestEntity, schemaDef, { dataStructure }); + expect(schema.redisSchema).toEqual(expectedRedisSchema); + }); + }); +}); From a7daafcf0c93a9973dc7e5bc60fc485a11af7739 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 30 Jun 2022 15:53:46 -0600 Subject: [PATCH 02/28] Create vector search integration test Based on example in RedisInsight-v2 --- spec/functional/vector.spec.ts | 90 ++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 spec/functional/vector.spec.ts diff --git a/spec/functional/vector.spec.ts b/spec/functional/vector.spec.ts new file mode 100644 index 00000000..05bf8d20 --- /dev/null +++ b/spec/functional/vector.spec.ts @@ -0,0 +1,90 @@ +import { createClient } from 'redis'; + +import { Client } from '$lib/client'; +import { Schema } from '$lib/schema/schema'; +import { Entity } from '$lib/entity/entity'; +import { Repository } from '$lib/repository'; + +describe("Vector", () => { + + it("demo", async () => { + // establish an existing connection to Redis + let redis = createClient(); + redis.on('error', (err) => console.log('Redis Client Error', err)); + await redis.connect(); + + // define the interface, just for TypeScript + interface Product { + name: string; + price: number; + image: Buffer; + } + + // define the entity class and add any business logic to it + class Product extends Entity { + } + + // get a client use an existing Redis connection + let client = await new Client().use(redis); + + let schema = new Schema( + Product, { + name: { type: 'text' }, + price: { type: 'number' }, + image: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', initial_cap: 5, block_size: 5 }} + }, { + dataStructure: 'HASH', + }); + + let repository: Repository = client.fetchRepository(schema); + + await repository.createIndex(); + + async function loadProduct(product: { name: string, price: number, image: string }) { + let entity = await repository.createEntity(); + entity.name = product.name + entity.price = product.price + entity.image = Buffer.from(product.image, 'hex') + return await repository.save(entity); + } + + const entityIDs = [] + for (const product of products) { + const entityID = await loadProduct(product) + entityIDs.push(entityID) + } + + // TODO: execute a raw search for the first product image and we should get the first 2 products back + + await repository.dropIndex(); + + for (const entityID of entityIDs) { + await repository.remove(entityID) + } + + // close the client + await client.close() + }); +}); + +// Vector values taken from RedisInsight example (hex format to make comparing bytes with CLI slightly easier) +const products = [{ + name: 'Mobile phone cover', + price: 50, + image: `55cb1d40f7d0853e18b63d3d120c913fd182893e323a703eac4efb3e8891213e520a03405d2a423d44fcc03e6bed1d3f48eaa43b0a5d863fd153bc3f4d8a023f000000004189713f41ef543ea1f74a3c434fc63ed24b5c3e92559c3db4066b3f6ff9c63e4920883c565b443efb7c063f000000001288fc3ee264d23f000000007303de3af93a1a3fc10fc73e00000000000000001f52403fc3c7fc3f03a7463f6a61813fe613d73c9132ce3f77ee093f794ac03fca66c73fc0b35d3f00000000cab1d63f4b08853fdb93f33d30b08d3ed9bc943cfdb7203c0803c53fe33f633f00000000a5a9963e524c7c3f2104253fe9db8e3e466a893db8c60a3f4032a33ffd9c583f00000000fb631f3f0e50383d7847223f7f5a5a3d9a5cea3ef0092540c341833ba534833c22a2333f28e6ba3e8a401b3f9b66a23b92336e3f2c8c9d3fcec1e43f744157404ef16a3f8a63393e4c422e3d00000000ffacd53eacf1803ec6de1f3f636aa03af052bd3e11c0bc3f1a24f33d437b043ea244a03e98a78b3dd86008407724a03e3f0a333dd676fb3d79ffd93d747c143f1f1ac83a874df33fe1f69b3f72cd9b409b945e3e3bd9043d6c12a13f186de03dc9ec293c1b83cf3d917a9d3d30b6513df375ec3d884c943d773f733db45ae13c6aee8e3eb7aa333fe8c64c3f6a97143f700d5e3cb63a483e2296393c0000000014703d3f94198f3e18c7153e7d2c4e3e323b413f54123f3d1026223de82f6f3d6a9d2e3fe2078d3f3796d33fadd6973e7b249a3c6f86413eb41e8f3e3d662d3f5123cd3ec1fd343f0498533fc48aff3dc8bf4f3ef64e3540dd13163eaa80143f5f70683ea7dee23faae9d13ec90d903fd62e173fc942db3c3203f23e68d03e3f6557793f6e37893f0330b23dea1f7f3e1f8e343e4ae1ca3eb21a303ffd6adf3e37c6003f0000000099f2213e922acd3e3736cd3e7d776b3f5ab7993d16f5453df6d5133bf4f0a53f6112343ef250d83dff01813f817b2840c5438f3e226e723e50b8da3cb6f5034026ca533c8754fb3e0000000041873a3f591f8e3f39f2323fdd13f43ef639f53e98f2e53f2bf24f3e3776af3f9ddba13e944cdb3e4c740b3fde93773e3c4af03d364fa93f3d52703dab40393f7601963e7441703ee654653fced4343fa787ac3f4ee4103f3db31a3ea803eb3e3983e93e000000003fc11a3e4e3db43f1df001402aca903cbf11503ec172333c720e2b3f49545c3d12299d3ebb57dc3f0e205c3e7de96f3f4584ce3f8196733cef6a583d4db3993d22567f3f253ade3ee27fa73fbb7a7e3fe5378c3e39ee133fccbd07401e6ec13fb65b0e3efdcb383f51a85940682aae3f64b1843d83a83b3fc0568b3e6c84223f5087863f3cc0323c671ae13c580a813fcaaed53da820f03d4d5b593df0e1be3f3b8bed3f21687d3f9ecfe23f0e15a83e9008a23f2abbf03db708c33e8df9384087c18f3f150f523e88aaae3e1588a83eef438d3ec74c1b3d1063a83e300c09404cecd03f0517cb3e843ba83e41e7f83dece4ee3ec359423eb3b9203fd982853e3fce723c146f813f365e9a3ef96f993fe8a1073e392b8e3f225d433d3c2dff3bde61a93faa56dc3e2cf810400545de3f1110ba3e0822143edeec7c3e65ab963eae98633f8308693cc5eab53d19e6bb3ec7a5cb3e9204953f117a5c3f886b6940d0fafa3e373f3d3f6a390d3ec5c7a53e00000000ce2f8c3ee5a7073f00000000872b783e4161cf3d32174f3c0000000054cd493c78c51b400fa2993d100bd03ce707d63fa1781f3f7c3ee53fe82053407cd9d13ed9a80840ac7a343eaa51113e2a51dd3f36c49c3cf4ed243f0f69093d1e915b3e28151b3e9a82a03c37b9ad3fb389713dc9722b40fa348e3fc337803fe789cb3dc8e6903f07308d3fffdee53df5e9243da795dc3ebdfb1b40955db63c3565133fc7803e3f0722003fdb87103f7994cd3f0668173c15e8cb3fa3b38e3d2aaa2d3e441bd43f099dd33ee53f2f3f1f94b93e0000000090ee613f598f484030ab283e843db83f0000000099e0be3f88d8793f3face13a41e1b83f5b8003406ece473f000000006b70893f5465cf3eb463623f3e849f3e70669e3b3682413f28554b3c5d368e3f7560243e7bdfaf3ec59bdf3ff82bef3dce4e423f0000000005b19f3ce434903eec712f3e40c8d13da9c3243e268ec23f000000002ede793e7ea20a3daefbfd3de6214f3ef9b1cb3fece9513ea77ac23ea9c4903e000000003fb7be3f6123b43e876b663ebdd6f53eef82303e6418a53f56746d3d77aa1a40da86a13fde72e83effd88b3d960bdd3d1d9d5d3e76da953f92c0ff3f8c6c813dc952e23ed130193fdd0ac03eac528f3abbcf393d87dc863ef3391a3f221d673fb800d73d2196973f00000000ef13a83e54a4173ef3fb2c3ffdadb43e00000000000000004cc0d33dc1539e3b5ba6c03fbbd9113daf0e413fcc62283d0ccb983d65da463e3fbd0b3f22c5d33e47f8773ea57e103ee1f03f3d2b12883b234c5c3e4889933f03a3e23da3f7993fc533663eb98ddd3f54a8b83ebcf5193a050fbf3f72fbba3ece4f313f516e863f510fca3e9abeaa3ffbe7fa3d3074843f0a758e3de8841d3ffb77b13e1fd14a3f8ce8ff3e2aa3c63b000000001610a93e0ab8ff3e9687b13e1c2b1c40637fdb3d91c6a83e16c98e3f6ce4213f628c383f4162fc3e7c44b03e8387803e40b5883c12622040229b0f3daf1c8f3fc044953ed1f0673e6197f33e3f09823f5809023eceea743fa310063ef20fa03cbeb4833cf394893fccc94e4065d7833e70a9913f28528e3d2e28a43e1053363f2136c43d1b34813daaae713f886add3ed587383f3260a93f2216503f000000004bac993e` }, { + name: 'Gold phone cover', + price: 78, + image: `262044403437ba3bac28ae3f51461e3f62a8223eff4db63edd1880404835053f0afd464091b6163fcafbc43f4e0c7f3f1695053f2ce8e93e68cc293fd0b6be3f51953d3cc338264054a5c63d779e163ebb82383f1418993e9ab8f23f5421b63f8187f13faee4aa3fe3ac373f0c919e3ee5c9883ee5b7083ef0ef15404c5d1b3f7f88073ce7c1064063e05e3fdd4b603d88d3ca3ea772a23fd6068240dbc6b53d678fba3e56516a3c1bd7d03faef2213fa5b14940e2f9dd3fff44023fa1a4a23d58cf463ff902953e00000000e5f50c3f45439f3f000000001076b03f799a003fd4cefa3e7bbef33e5dbb1840c026f03f70a1113faa22ed3c703b563dbc67653f28d4703f3c67f43de1426e3da23a0c3e81ddb23ea8c5873ceee9be3e45e86b4041fc943eee20e13dcad90c40fd711e3fcaeec23e3822153dc97dbd3ffbb3b93dd428e83fde0a35401268ac3fb480c23d94e6b83da2cc4c3fe8dd8f3f6618c53f5b7c723f38f3d23dee29883f1274aa3ff400c93e8acf093e0e9dbd3fd01b133e5b7063408cf5423fec34323e8071453ec9525d3e229baf3fa667423ed877033f33adaa3f73bed43fbf47c43dda57a53fc12e7b3ed0faa93f7206ba3e00d8e33d8f819c3ee17bb83f58b68a3e5e4e4b3e257fb13d54d1a33ef8cc223e2cbdf93e3bab5240dd229d3fc9992f3d01dadd3ec722033a1abda93d9d96cc3e0e902d3f52a9f33e6317aa3e63b1223f5733143f352c1b3fa52f263f805d083dddf511403da10f40f6c3c83ed079463f4ebb253f1074603fef26bb3ecc305f3e99f85940eb01c83fb890983ee616433f775a693f05c5fd3e92362f3f62adcb3e47020a40bc04493cf5dd813f6341ee3d5df2a03e0000000040f4183eec8211403603843f7077e33fcd899e3e0553a03fccb159405b96493f5456903e0000000074be4f3f1646313e1344263fde99443e8007aa3eb4f69b3db728423e6fd9963f05809b3ee68fc43f66fdb43e0a6ec13f5f79f33fe8151d3f59e7293f76d6e93d852e22405247d73e78943c3ee6de3c3d55a13a3f6a90933f0ab03f3e5e34713ee644ce3dd9a4ed3f4653213db4a2233fe3f9014005f7a73fa2821b3ff262903fa872383d4c964d3ec2721d3faf01af3e827e933e9bdf533cf36dae3f23b89840c457793f032eca3fbc19b13ef0bb6c3da856003f000000003489d73bbbde4e3f74a48040d65ec23d25182b3f0a851e3e2304803f5b00ba3cb60b3f3fa75c0a40f079f53e8579493f1a5e2440f954a13c00000000ad71143da38f763f4d0c2d3f1f7fb53f80ffe33f8d79683bffa0153fafe7353f98e7124012c7b03fb70a553fdb4c45402fe9733e95214a3f33d3134018d28e3d5b57093f2f9ce63fea7edf3ee343d03fee141e406c6a863dfb5b033e5f50213d36c8564009d3533fca99353ec53d633f3f07183f0d6b424006e9803dbb9ac73ceab17e4055fc863f1e97d13dc460ec3e3617233f91a5b63e052af43c16b08c3e02a8143ffa9d8f401338803d04ad833e41da0e3bf8489b3f493a4c3ff2dfe13f877242404e05033d09e732402fb00d408162a13fa5c9453ec1e72e3ff0358c3d3f78d13fcc67b13f1aadc43e10c7814040f1c53fbbd2303f54c78a3d1dea963edf1e9a3f0990c23e88ac593ea3e8e43e7fdcc33fc812b83eac02b03fac67c53f8d4db440a560993f90308f3e4c20483d5ac1023eb963f73abf18463f14734e3f1c228f3c60319c3e410df23e8ce1c63f000000007c9bc43d840e444000000000bf42823e3dfb123f18a0083fca75ce3f5e6ad23f1b41403f631b224083a3f63e288b0d3f9f222d3f00000000965c0140d50eb13defd0903f1e36123d9fc6c63e0736e53faf4a1a3e5b2d3e40366e903df00ca63d04d3423da0240340492fd63f8051023f2273663fa79e4c3d67613e40b079033d72cac93e98910540e72f2e405933ba3b8d26563f2dd19e3fb090b53f3780a83db3c4d73eb7ed4f408ccd0740ac5f583f72e8ce3e369bc93dc05bc33eff658140a05f083feade1e3fd662fe3bfbd1ae3f3d3da43f2114653d0498f63f43a3bf400723433fb6768c3e5286623fab24853f8503e73f612fd43e04f8623f703a803e7cfa853fe9bc813f9146a93d5e74ac3ec356af3f5c7d903b6e3f8c3f000000009a9bfa3ef848ae3e194f4a3f122e3c3e5b39213facc8573f2210523f363c7b3e6e29783e21cb193da636d73f1a5c0a40bb1cdb3ed230973fe136e63eea12b13d7267493fff47833ff40fdb3dc7e5633f11e0683fd656ca3f04c18d3efc6fcf3ff0ec473f2faf3f3f10060b3e4109f33ee2835b3c34538d3fa86d5740b6504a3c1907b93fb22e3a3e79accb3e5fedbf3e7fa8903d7909303e4463ad3e7f09643f4edd7c3f7913393fe822163f7f3c034039b3373fa7949a3f07a7bd3f347b7d3e49c54b3e7824d23f8710b13d44bd14400ad4f63f88ae393e7388f33d07a64e3e3b400d3f46c1023f9634b03f9f32033c0800253f28fe833ea1e9c63ddb37453f3396533f08d3a43c2c72543f9be3ec3ffcd7a340f4c2cd3ffc4b3b3de32b133fa1c10e3fdae2f33e68cbd93f0c640540ec071940a8659b3d5bd1793fabcadd3ece562a4087010f3e5dcb913f15c27f3e38ddc63def334d3f7901843f1402743e1422ff3f184b6a4045c4703f3735eb3e4758503f093c033f45e5223d4952d73e9939253f146dc13d9fdf293f94891c404efa843f346e623f49b9a23f44536f3f34d46c3e5e28783f00000000f92b8d3e6a09403f1984163e83f7a73ef833ae3fc8f52e404e42993fc761753fac9fa93ec9c4a53e5517bc3f1447463bc48a263ed979613f4726f73e36b6bb3c0d9c3c3d6c5b953f6b222b3cf46afe3e`, + }, { + name: 'Patio Light', + price: 120, + image: `35d4113f32cdd43dc803043e85ff453da392643fa1b3da3e12cc113e5b99db3e7401653fe23d213f2be8953f54c82d4080137e3d23bc953e2392843e2317104000000000ab58703f44826040aed8a53fce99c33f9146a03e2284283f0a659c3edd996a3ef619ed3f5edac53e0923853ed974403f3b13fe3f5b81b03e01ac1c3e6e0de63ec81f723f2a408c3ec8398b3f98455d406e52333fb43cb03f0d6fb53de6910c3f9a54843f92ad0e3dc788bf3f720c673f778b643f2354cc3f265b0d3f3337983edea2413e537a1040486a6b3f2e567b3f1668db3fbc6152409df0cd3f314d9c3db2f9893fc5c3053f72cca23f4760d13e04faa83f95f9543eab420840548f0b3f0923143ec5a6b73ff85aa33eb201aa3e5617fc3eaa557f3f190d3c401b77fb3f8735443f03a3853d9503f33f2284be3e10c8253f3847503faae4753f33109e3f15c6df3ff6b4d63de8310d3f059932405487293fe86c923bda5a373e479c3d3eea87cf3fd8367b3ff6c76e3f660de43cd0d69a3eed00163f9d0e0e400a175c3f9fd8a53d00000000e8be963ef83a673fda9a933fe1651540b9a34e3efc29df3dcada8d40a85cac3e14150a3fc800af3e39019b3f4d048d3fa3dc6d3ff0730f40c95bbc3eeaf9ce3f20b1203d801fe03cd1fbc93facb54a3fcd915a3f4457a13eac1cae3f132b193fe58b5a3ec7a57f3fd6ce9f3e18988c3f485ae83ebd88f23e37832f3ff981c83ee23f2240db66a03f5ee4343efeac033fe7021a3fbe47a13e7265f13ef0d47a3f10541d3f5fbfca3db286dd3e7a30983e37e4f63e409dbc3f52c5233e4159323f61a2254068f6183fe179483e5a38453f459a2b4095c0a83f2574b93ecd5fb63d1c00a43ee86f513f7046f03ff34eb63fa35ea03e814cb03fbc4aa93fdc7d1b3f6528993f72d1673ff7b8c23fdb0e8e3e58643c3f3fff293f59ab413ed65a013fc4eab53f7b75373f6a2d453f2637283f03d8563f28bdad3c38a1b33e112c313f90e2243f0156ac3fccd5803f34faf73d7bd4803e3b04cc3c7779a73ee6e1c93feed9323fc1128b3d12151f400de8b53d6f09cc3d0d02373fc850f43e79c7a83dc573263fe35c5d3fc9bfd53bb26aa63f96d1a43ddb6d163e2c7eca3fe6ad363f9963283f0d09983f7423063dc522333f8a02573f851d2a3f39f9fe3d0169143d4cc59a3e16f0fa3fa1ad213fb937153f23ded03dc4e91f4078c7893f000000007d0f223fc54f933ee108c13e9bace83fcba50f409223d33e8b8e993fb336db3edd442e3f2555c13ed40cd93ea618043e901ce03f0573da3d5573293f388e023ef6c6a33c63db193edabb334036be2b3fe24c893f22bdac3fff31bd3e087bb63f647c9f3ef4e95d3f30dead3ff9747d3ec386263fcf2c0e3f74d9ec3e6cfb9b3f09c2b23e80e3a13f1988733e15b7ca3e689b1e3f4716933f840ae03ea1a52540ca2b533f227c883e63c1073e2558ca3e70e9a83e1668b13f133e213fbb9fbd3f0d08723ff9f1553f2f09f03eac3cbc3e8d1b9c3f07e81e40c85e213ddd4109403fbe863eda0f3a3e0462cc3f3768ad3e140ebe3e5b3ab73e94cd1340ea89be3fe647483d7c150540830b173fd4bf1b404379093fb73fee3d6c37133f1d80ca3e9a99653fc979aa3f8ffb123f2a52143fb971373f9807923ff6ea3e3f5a05e73eaca1793e21db3440f7c0e13e784c514059cf943e33d3553f0fb2893cc4c655405f0e3c3f40b11340dea3233f52301b3f76c8ef3f9d1aa93e9ac4553e807b793ea599573fd9872e3f805b6440e69cf23d95d1ba3e22150d3ff4c3fd3e165f3740213e803d4813bd3f2c33df3edb8b8e3ef6de2d40af40d33f7949813ef011613bdae2e13f454d8b3e684c763fd22a953fb699963e322f583fd98b1a3f2f39283f03f1733f4d51f33f3c253d407601643e14282a3f3fb42e3e4d03263f24d0963ff962154001f0823d38d7f73f03dba73ed430893d3f8e263fe5319e3ee5c5de3f99d39d3d4e42404061ae2240918eb43fd6b7443c0cd1a53f77a7c240d6ad223f990db73f7dde3f408764ce3f3facc23f837dbb3e3aa39a3ea1b9de3c10505a3f7b7e443f03187a3f7c23b63f3952523ff8121d4062f7733fa331fb3f6825ee3c32bf0a404441b63f4d9c4f3d12ec7d3faffa853fbc940a3dae88823ff98b1c3f1b3e5a3f5158353e619bbf3db74e433fb9a81e3e096e5c3d2c7c7a3f5be0843eac75d13de194d23fe368a53eecd1903f417ceb3faf9fa13fca7dfb3f1157313fbb18d43e5d33ea3fd001af3eeec31f3e5f12333fd54b3b40129f993fabe81b4087fba83e11319e3fecc5013feaa4b23e79010e40a26dc33d4120b63f4409bb3f43a5473f9d0f533fc501913f3218673fda34833d7637fc3d1a70dc3fd6a8d93cfc859d3d18c7503f0c07a63fa2cf1f3fa7d2ae3f557a4d3e199ee93f944b723e8a30483c25ae3f4034b98e3ebc10263f5a5914401da23740f77cc73ef21a703f9f297a3ff63f8e3f25e7044021846f3f65a61c3f4c953b409ff8593fe56bb33e703bd03d2a84283e9a22c540cef5733d66873e409c4d963f896b373f4ab0a43e15555a3ec4053a3e3737f23eca13893fe17cb53f38d4943ffcaad23e0d4bb43f7492113f2ea7233fe56fe23efccec23f2245733e18c5c63ff678373e1422983f01e3ce3fea06323fd9258b3e3932cb3eaa2bcb3f5fd6073e90af3b3f2892f83ebd710a3eb4561440c1133c4021d3234007da1c3f7f2d1f3f39150640bf045c3fe337543c5d0b863f0a3e903fa5faee3fa27f6c3c6a3e673fa8891f3d7cb28c3fe132b13fb9d5d43fdea3b43fd9d7383edd9cdd3e85530f3c5a43dd3e2b151c3f6533b63ef8929b3fc2311f3ea534803e656dc93f`, + }, { + name: '2-seater sofa', + price: 400, + image: `a8cd873f83e1553fe701173f3fabc83c9fd6613f51aa343fb43b883ff173083f207d943ffa6e19401618a93ff600ff3fc410763f493d443f5d579a3f1f0ddc3f4e0bfd3d25fc2b3faf43453ed146783fb498713e486bcb3f8a7c6d3fe7e9aa3f59482b3f1c34013f03fdee3e9e412940035a313fa5967d3e7983043f1f93393f5220233f85d9ea3dd6eacc3db48e243ff22f414038947d3e3c784f3f381ac33ff128a03e51cfcb3f81716b3f3fddd83f3d5b063f3bf4f63d50a1a13ebb111040f7a3573e12d1963e78a2ba3f8d05053fe474103d3f03d53ec12b2a402ae43b3fb0ea613facf0573f032c0f3f2e22b83fdefebd3f631b6e3fddfc823e2816d43d0a2dab3f5e7e653f3f67423fda7bcd3e7f3cde3e75530f3f094e233e225bb43ee528113fc4de713ec0ab4b3ea6baad3fd3c19f3f68f4473d49b8c83e416bdd3e2c94673e948f893f7b8c4d3ebf903e4003837e3ea7eb633facd6fd3cb4930d3f32d705406237a63fc97c2c3e7ae4143e98b9ba3e5b4e2b3ea6e24d3f67d8053fc4f049401a59623fb426be3f9fcbff3e5904153f707dc63f811bbe3e21c9833fda22163f9fa9f03ef39a3d3d8c381c3e2e3d2e3f41453c40ae0f1e3f0b721f3f8afe9c3ddb492d3e1b72403fa6baa13f2a517340482af53e10213e3fdbfb7d3f014e473e283b2840a4289a3fcc29e83f1b6af73f484b043e8420de3fd4b5853ec48a9d3f3784aa3ee14a833d1556eb3f6d5b933f5f64ce3f908ebd3e1452493fc161cc3e0ad08e3e122aae3d15676640394cbe3fefc3d43e905dde3faf9c433e8622a23c9d04683ea009104052cbda3f24689d3e5ee3b43fb2b92e40000000004c87e13fc3f3ae3ec4f2af3e4720083f25763d3fa767323f8a506f3ee395c43f5e9107402819973e8a49033f806a9b408e8c883fe15a943f372dcc3e22ff1b3fde3bae3f21c9a33f2259803e07d15c3d8576fa3f4d45d63e6fdc3c408d41b43f7824fa3daefb853e1a6dae3d167ce73eb7b20b4054a0963e7db4c73e74f1484004fe7b3f29e31f3f0433183fa9191b3f7280573f91746b3d3d17263f1bfea23d833b1b40099baf3e22d58a40086bff3d794df73e56d56e40bd531c4034cc8b3f5801a83ed4efed3f18ec3d3f770e043d7b82823e12e90d3fa55f033f967fb13f14cdac3ff35e6c3eb30cd43d5272373ede6bdd3e283cd63e7663573f907ad83e21c31f40de97803faaed643f1266a93f5451153f375b433e9a86ad3f4eb6d63fb8aa233f75a21040a776723f83d4f23d5aaed93ee6405d3e49b2063fb465853f7e5a143fccc19d39a2e8283f700b023f58e1d03ee1a01b3e7d62ac3bbf1adb3c25f87b3ff9d2283e30daa73f7953203f23b8533f3cc0833fa593403f339ab03c143e733f9d28f03e19e5d23ff342a23ee1e1683e437e4f3e8cb9bf3e16cc2a3f40d7033fccb4bb3e22258b3fec446a3e9d0ba63f7f94e73efb7fd83f651bb13e894c883f18b45c3f9f0bfe3e11b0ea3e52bd813fb88d9d3d0574043fdb05ef3e3931eb3ed82f4c3e7c688f3b28be013f988eb53e5db9e03ff755423feede163f8af6253f2adb21401259b63f3082963d2c7aa63fc7cfa83ef2cdf63d6c88133fb6541f3fbbf2c73ff0a2ec3fac75b13eb92810407cd5a53efda7003eb9604e3ee31fa93f32da173fdbd0383e402d2d3f964f2a3f68b0c13e45c81a3f94f4f03fc1ada33ea363bb3d4459e03ced6a023eb724f33e66a7093faa88cb3e64e2153f88feb83ff31d003e4708933fca7bf63fdf02c23eae2fb03ec7db133f4ec5153f50f5b13f5f25423f157f8c3ef9e8fd3e3991353fa1eb243ed4703140ef72af3e2a2ba43c386b143e8cd4843ea74b443e6895f13c7f2d0b40da5731405b33653f0358e93f799ba83e89b4ef3ed96ac23fe352463f6b9d823fb685aa3e3cd3e13cb2fd1540cde8fc3ebb39103f5e3ac03e0e6dcd3f78be373f7759bf3f33e6833f94309f3f50b4653f00000000f77f0840d619cb3ff0b3353fff7dec3e50e2483f95693b3f47b43d3ff7183b3f2846e03f6b0e4b40bdd7423f81eea53fb498853e10b02240b914253f3495443d10e8323f7433483ec569773fbf90f83fb450063e2c89373ecaa807406569fa3e1d708f3fade6143e2b07943fa77e9340108d2540a57d7a3e7854093f0729643f55e22d3f77020f3e946ed33ff9f025402118413ea7541f3f3792a63dbdf4933e7cd6363eca9e773faed1813f0715753e016df83de1730b3f7084113e66893c3fff723e40571882405306903f7b988f3fde962a3fb7a4a33ee17ce23fe1a02e3f8cf18c3fa3d9ea3f3d7ccb3facb2873f8d0e793fc7e02c3f1f4de63f9c2b1b3f30345c3f8e42823d49aab43d9b56e63f61add23f9072b93d7013dd3d47994a3fdd49b33ef83ea03ec813c23f2ab0233e3707e93f142e4e3efbf68640ef4bb23f053fd23f41829c3eb8404a3f5d41833e43d6a73e6e74063ba86f813d3fe3d43d1eb2af3f8841c23f1fa06f3e3f11e04022512b3f34ccb13e9ee8b23d7994c03fbcf8ba3f925fea3fd43ca53f3c66ca3e0e2bad3ca22fee3f70ba733f4ad3713e19ff6f3d4ca77a3ce2b3623fd18ef13e7718d93ee0be9e3f78211f3fac1c1640147741401f697c3ef5ff193f4c20283f01ea9d3f74903c40d9decf3f67420a3e4a1e7f3f4402aa3ee3f8413d9e3ec73f5a22d83f55700a3f48cabb3e99feff3e580d813f5581eb3f59f5803fca4cad3fd6ba1b3f051fdb3e2284a53f4a9f174077eed03e3205163f0bb4243f70d1c43fc7e72b3f66590e40d5c2873f22f1283f8d6e713fc359c93e58c0943f8a66b13db2bfce3e5d28303dc8f7543f3fb0c73c2ddd8c3f94db23405042443f6241a33f37407d3d`, + }, { + name: 'Comfy Chair', + price: 200, + image: `5101003f8b25923f1db69e3f1465113fdec3993b1000813f321fb33cc1d53f3ff9e68e3f2ec10840c869023f4082b03fe1711b3fd0fcff3debc3753e7086be3f1f2f8d3ec3acbf3f5059433fc8e2e43eae18093e6a935c3fafd41f3f3b48fa3d2e2a8a3f00000000688ef93e88a4083fe8439b3e33428a3f2b2ce13eb09d263f8c44113eb0fed83e907fd43eb90bca3d38c21c3fe1b4c23e87426e409de2a23da3030b3f0f0e8f3fb919283e414c883f98c7ca3e4cbcdf3fe767a03e4148683d433802400059173e6cb4c03f362f1240db64b53e9560613fa155c03fd5a7bd3f6a7db83e167a843f9bb5433ebfdcd33f3c72383f8dff673e785d9a3e6bf5223ef08e8e3fc4fc153fba7a8d3f4cf9bd3e32ab593e3b8f1e3e03e3813fb896a73f3f7e473f157b463e59306a3fe8ff973cc794b33f3fa74c3e14af573e1f9a85402631143e83fb8b3f88a8b73af8f9013f4df51540a799eb3e45fa1a3ef6d9223f67ab8b3f3faa6a3e951fbe3fbf33903fea9a853e3d10123e66435e3e5599c43f44b90a404869bb3e5f908f3e511bbf3ed111713dc77bc03d17ac0e3fd63b8f3f95c1353d826f83409d0e103f8965033f9e9d313f9e0ecf3f65760a3ed57a703db26e0d3e08f8bd3d6ea78d3f21428f3e65a7803f12c2df3f7b97083d6e8abb3f70af883f197a753d7b3e4e3e8096023ef760803fbde3283ccad13e409eb84f3e3ff1503e5bc0833fea91bd3e7377d93f039fe23f764e2e3d4eb4e73e65c1b03e32989b3f0a1f133d4a63833f2c8ea43fcc8a253fd84e6c3e0c59883e98b1713d3435653e22673a3e4d00eb3c7dff163fc0a1b03ed98f493f1a251f3f08d9783f83b6dc3fdf001a3f6149983e8083f33eb816643f1569023ff33dc63d5ebcb73e874a6b3e50d2873e28798f3e89764a409138da3b6a9ad63fa7f8503e14f51c3d49ca793e44015c3fbf65603eb9b2f93ec8bb8a3e1822ee3de17bfe3fd93a243fdeba0e3ef2f7553e657d8a3fa86ca53e9e64613e22a20c3e5e55af3e2eb2b03f928c323fccfec63ee880423dd2b9e63d7d602e3e2a288b3e2525a93d9abf483d0ccfaa3e7f0ff23daa57c340cef7d03d256abe3e44d32d3f1fc9703fe3874a3f847eb23f386bb73ff0dd3b3fd474bf3f085ced3d2a10b23ea25dd13f98b39e3fada5803f3257853f8f830d3fe81f9e3ebf50c33e72e6c43fe154c23fdb64ec3fb820463da1fc403e39809d3e482ed63f4d3fc83dc7cf9c3f59f4c63eb56ba23e9ab9f63ef423ba3f674a793f3f055d3d1d7c063ec4b7303ff32c5f3f0a18ca3ef87d5a3e513a1e3fec22f73c2f11263f6eefb13ed98a7e3f386e243e8cdd12406135023f32dd7e3ff9dd963d2a77393d839d6a40eabf193cda02ad3e0838433f65beab3fa68b043ed03d653f16ac483d9b43c33daf02f23ba565863e66568a3f8f3da23c4ed8ee3f5ed0223f7682693f7cece53edb2e6b3fc4ad293e829c183f2146003e6c600c40a684bf3f49e96e3dc126313fe24ec53ededa783f7823a13de7bbe83e9d39583f9f3f333e04c7613f61d4343f61a3463d66cf583f6cf0b13ee1ac463fe5d7843fb9fc353de59aeb3e509cc23e11bf7c3d447f103f9ffde43fe1dc3a3eb34a183f301e3c3f7feb453c9242683ec4c12b3e82e3133f557e6f3c2f2c443f8a1b01409042893f943d853f4e114d402ab7a23f5d09483f1d3f0f4083ef623ed61f433ea544d43e0e92fe3e38f0283fea7d033fb8288a3e0dcddf3fb78cde3e28ab2f3f84854340548b473fc758013b78449a3ef5b6803f9b65ce3f96d5603fd2928e3fe15424407479e53dff78c13f395f0440f025b73ef9b2a33e6ba2373fa51f5a3f30f1143f895eaf3efbdb283f22ae333e95d2e73f45dce33db2070a4091e91d3ef8d98e3dd9cfd03fb46e7c3e2fe8433ed15dc53e7092893fea6e853f48a48a3f2646ea3f63e98a3eb31c2d3eb722593eedc1883ed26b8e3e114d6a3dac019e3f4e9f943f1567b23f6f6a254079d3243fa5ee5b3e70fc0e3f5b894740162a873f0e14d73f625f0e3fecf84f40fc360d3f22adf73daa6cad3e30212c3f01a68a3ddae0393f3248703de8afad3dabd0e23f7949083ec86c7d3ffd2dbf3f091eb73e5f6d9c3da6b7223e6b3edb3e150c9d3e81363e3fb420be3f9de9ba3bf3dcdd3e8f99113eb9cafe3d2ceb3b3fa558ac3f7356063eb236f93e1d4cdf3ecc5db53ec4b2423ea2b5823fdb19413e4a57603f8bac1c407d57c53fe2e25b3f84399e3fbcf9973fdd93153f498da93f3c53623ffb929e3eb7a6343fd4f8f63f768dd13f885d153fcdd11440befe8a3e6ee900406d75013f95e97f3f54b4303fb37a953fda9ce23de70c3c3f747eb13e6efe913de2cf613e68a5633e19cb633f1a228f3e0c71b23eb5718e3e9d06ec3faf5c2f3e5907103f592ccb402128463fc8e2e93e6ed22e3ff61d243fef81f43f9535b03f84a22c3f86689d3fc3050a3f7d209a3e28ae033f8c62883f486c283f39a6d93d44d28a40d4cecd3d019c363fefbeaf3f7e30923eb28d033d30db343e77a3f83ed185023f18fe7f407690d53ed066213d58ad983efda3723f2b6ab83d6adee33ddea5ed3d3f87813f40cc033f48cb953fffba163eac9bca3d74c7923f262fdd3ee5080a3fc40efb3e99692d3f80573c3d9622933fa2b8aa3e186afa3f5dfda63f6b9201402212e73f6fa8033ffb78123fd70da43f07899d3cc171b13fd1f8f83a68ddf33f4d84e43db9ac8b3f1b6b1940d171503f224e153e6a9c773e31650b3f5baa283f30c2bd3b00000000623ad03f70482b3da918923f7c6cc23de80dd93fc586f33e956e743f26a0a93e61c4b03e2a787e3cd9c7bd3efbe1d73fdb3ca13e5a601f3f1fc9623e`, + }] From 0d1ab377b83e87e953a43c229a2b7e1dc079ff4e Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 30 Jun 2022 15:54:48 -0600 Subject: [PATCH 03/28] Allow setting Buffer field for hash data --- lib/client.ts | 2 +- lib/entity/fields/entity-field.ts | 2 +- lib/entity/fields/entity-vector-field.ts | 22 +++++++++++++++++++++- spec/unit/client/client-hgetall.spec.ts | 4 ++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/client.ts b/lib/client.ts index 2b338d05..c77a0eb2 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -11,7 +11,7 @@ export type RedisConnection = ReturnType; * Alias for a JavaScript object used by HSET. * @internal */ -export type RedisHashData = { [key: string]: string }; +export type RedisHashData = { [key: string]: string | Buffer }; /** * Alias for any old JavaScript object used by JSON.SET. diff --git a/lib/entity/fields/entity-field.ts b/lib/entity/fields/entity-field.ts index a6893326..cc30d59a 100644 --- a/lib/entity/fields/entity-field.ts +++ b/lib/entity/fields/entity-field.ts @@ -44,7 +44,7 @@ export abstract class EntityField { return data; } - fromRedisHash(value: string) { + fromRedisHash(value: string | Buffer) { this.value = value; } diff --git a/lib/entity/fields/entity-vector-field.ts b/lib/entity/fields/entity-vector-field.ts index bd11ac49..9eff363f 100644 --- a/lib/entity/fields/entity-vector-field.ts +++ b/lib/entity/fields/entity-vector-field.ts @@ -1,6 +1,26 @@ import { EntityField } from "./entity-field"; import { EntityValue } from "../entity-value"; +import { RedisHashData, RedisJsonData } from "../../client"; export class EntityVectorField extends EntityField { - // TODO: implement! + // TODO: is vector index supported with JSON? what format do we send binary data in? + toRedisJson(): RedisJsonData { + const data: RedisJsonData = {}; + if (this.value !== null) data[this.name] = data[this.name] = this.value as Buffer + return data; + } + + fromRedisJson(value: any) { + this.value = Buffer.from(value.toString(), 'binary'); + } + + toRedisHash(): RedisHashData { + const data: RedisHashData = {}; + if (this.value !== null) data[this.name] = this.value as Buffer + return data; + } + + fromRedisHash(value: string | Buffer) { + this.value = Buffer.from(value.toString(), 'binary'); + } } diff --git a/spec/unit/client/client-hgetall.spec.ts b/spec/unit/client/client-hgetall.spec.ts index f6982b18..dc5b2a90 100644 --- a/spec/unit/client/client-hgetall.spec.ts +++ b/spec/unit/client/client-hgetall.spec.ts @@ -1,11 +1,11 @@ import { redis } from '../helpers/mock-redis' -import { Client } from '$lib/client'; +import { Client, RedisHashData } from '$lib/client'; describe("Client", () => { let client: Client; - let result: { [key: string]: string }; + let result: RedisHashData beforeEach(() => { client = new Client() From 3991489babea0e5cb5c6dd6c12bb0728659ecff7 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 30 Jun 2022 16:06:53 -0600 Subject: [PATCH 04/28] Change how hash data is written to prevent Buffer encoding Redis client changes encoding when passing a JS object to write Writing fields separately correctly encodes binary data See: https://github.com/redis/node-redis/pull/2139 --- lib/client.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/client.ts b/lib/client.ts index c77a0eb2..4c395a96 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -213,11 +213,13 @@ export class Client { try { await this.redis.executeIsolated(async isolatedClient => { await isolatedClient.watch(key); - await isolatedClient + const cmd = isolatedClient .multi() .unlink(key) - .hSet(key, data) - .exec(); + for (const k in data) { + cmd.hSet(key, k, data[k]) + } + await cmd.exec(); }); } catch (error: any) { if (error.name === 'WatchError') throw new RedisError("Watch error when setting HASH."); From 48636efad1bbfb0650395661a27a2d0a7af15823 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 30 Jun 2022 16:51:21 -0600 Subject: [PATCH 05/28] Nicer solution to Buffer encoding issue From https://github.com/redis/node-redis/pull/2139#issuecomment-1131646750 (doesn't appear to be fixed, even in 4.1.1 release) --- lib/client.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/client.ts b/lib/client.ts index 4c395a96..86588ea3 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -213,13 +213,11 @@ export class Client { try { await this.redis.executeIsolated(async isolatedClient => { await isolatedClient.watch(key); - const cmd = isolatedClient + await isolatedClient .multi() .unlink(key) - for (const k in data) { - cmd.hSet(key, k, data[k]) - } - await cmd.exec(); + .hSet(key, Object.entries(data)) + .exec(); }); } catch (error: any) { if (error.name === 'WatchError') throw new RedisError("Watch error when setting HASH."); From 11945ba8aaf01f1ee5fb03b55ea9cdf83c31c70c Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 30 Jun 2022 21:12:00 -0600 Subject: [PATCH 06/28] Vector index is only supported for HASH structures --- lib/entity/fields/entity-vector-field.ts | 8 +- lib/schema/builders/json-schema-builder.ts | 6 +- spec/unit/schema/vector-json-fields.spec.ts | 128 +++----------------- 3 files changed, 19 insertions(+), 123 deletions(-) diff --git a/lib/entity/fields/entity-vector-field.ts b/lib/entity/fields/entity-vector-field.ts index 9eff363f..2b3bb529 100644 --- a/lib/entity/fields/entity-vector-field.ts +++ b/lib/entity/fields/entity-vector-field.ts @@ -1,17 +1,13 @@ import { EntityField } from "./entity-field"; -import { EntityValue } from "../entity-value"; import { RedisHashData, RedisJsonData } from "../../client"; export class EntityVectorField extends EntityField { - // TODO: is vector index supported with JSON? what format do we send binary data in? toRedisJson(): RedisJsonData { - const data: RedisJsonData = {}; - if (this.value !== null) data[this.name] = data[this.name] = this.value as Buffer - return data; + throw Error(`Vector field not supported for JSON`); } fromRedisJson(value: any) { - this.value = Buffer.from(value.toString(), 'binary'); + throw Error(`Vector field not supported for JSON`); } toRedisHash(): RedisHashData { diff --git a/lib/schema/builders/json-schema-builder.ts b/lib/schema/builders/json-schema-builder.ts index cb5c4152..6552e904 100644 --- a/lib/schema/builders/json-schema-builder.ts +++ b/lib/schema/builders/json-schema-builder.ts @@ -57,10 +57,8 @@ export class JsonSchemaBuilder extends SchemaBuilder {}) + describe("Schema", () => { describe.each([ - ["that defines a FLAT / 512 / COSINE vector for a JSON", { + ["that defines a vector for a JSON", { schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' - ] - }], - - ["that defines a FLAT / 256 / IP vector for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' - ] - }], - - ["that defines a FLAT / 1024 / L2 vector for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' - ] - }], - - ["that defines a FLAT / 512 / COSINE vector with block_size for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', block_size: 512*512 } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'BLOCK_SIZE', '262144' - ] - }], - - ["that defines an aliased FLAT / 512 / COSINE vector for a JSON", { - schemaDef: { aField: { type: 'vector', alias: 'anotherField', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.anotherField', 'AS', 'anotherField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' - ] - }], - - // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing - // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence - ["that defines an unindexed FLAT vector for a JSON", { - schemaDef: { aField: { type: 'vector', indexed: false, vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'NOINDEX' - ] - }], - - - ["that defines a HNSW / 512 / COSINE vector for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' - ] - }], - - ["that defines a HNSW / 256 / IP vector for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' - ] - }], - - ["that defines a HNSW / 1024 / L2 vector for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' - ] - }], - - ["that defines a HNSW / 512 / COSINE vector with M for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', m: 8 } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'M', '8' - ] - }], - - ["that defines a HNSW / 512 / COSINE vector with EF_CONSTRUCTION for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_construction: 250 } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_CONSTRUCTION', '250' - ] - }], - - ["that defines a HNSW / 512 / COSINE vector with EF_RUNTIME for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_runtime: 20 } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_RUNTIME', '20' - ] - }], - - ["that defines an aliased HNSW / 512 / COSINE vector for a JSON", { - schemaDef: { aField: { type: 'vector', alias: 'anotherField', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.anotherField', 'AS', 'anotherField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' - ] - }], - - // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing - // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence - ["that defines an unindexed HNSW vector for a JSON", { - schemaDef: { aField: { type: 'vector', indexed: false, vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, - dataStructure: 'JSON', - expectedRedisSchema: [ - '$.aField', 'AS', 'aField', 'NOINDEX' - ] + expectedRedisSchema: [], + expectedWarning: null }], ])("%s", (_, data) => { class TestEntity extends Entity {} + if (data.expectedWarning) { + it("generates the expected warning", () => { + expect(warnSpy).toHaveBeenCalledWith(data.expectedWarning); + }); + } else { + it("does not generate a warning", () => { + expect(warnSpy).not.toHaveBeenCalled(); + }); + } + it("generates a Redis schema for the field", () => { let schemaDef = data.schemaDef; let dataStructure = data.dataStructure as DataStructure; From b2d61d9aa32550ede91c56b4191fef4dd9e617e9 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 30 Jun 2022 21:15:17 -0600 Subject: [PATCH 07/28] Add note to revert hSet tweak when fix is released --- lib/client.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/client.ts b/lib/client.ts index 86588ea3..bb5c2414 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -216,6 +216,8 @@ export class Client { await isolatedClient .multi() .unlink(key) + // when redis/node-redis#2139 is released, this can be reverted + // .hSet(key, data) .hSet(key, Object.entries(data)) .exec(); }); From 2629cec1c287aaeb56a43f9ffda265618fc145b3 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Fri, 1 Jul 2022 13:43:45 -0600 Subject: [PATCH 08/28] Change `vector` field to `binary`, keep vector as the index option Store binary field as Base64 string in JSON (need to check on best practice) Add unit test to verify vector search operation --- lib/entity/entity.ts | 4 +-- lib/entity/fields/entity-binary-field.ts | 28 +++++++++++++++ lib/entity/fields/entity-vector-field.ts | 22 ------------ lib/entity/fields/index.ts | 4 +-- lib/schema/builders/hash-schema-builder.ts | 2 +- lib/schema/builders/json-schema-builder.ts | 9 +++-- lib/schema/builders/schema-builder.ts | 6 ++-- ...finition.ts => binary-field-definition.ts} | 10 +++--- lib/schema/definition/field-definition.ts | 4 +-- lib/schema/definition/index.ts | 2 +- lib/schema/definition/schema-field-type.ts | 2 +- lib/schema/schema.ts | 5 +-- lib/search/search.ts | 3 +- spec/functional/vector.spec.ts | 21 +++++++++-- ...lds.spec.ts => binary-hash-fields.spec.ts} | 36 +++++++++++-------- ...lds.spec.ts => binary-json-fields.spec.ts} | 8 +++-- spec/unit/schema/schema.spec.ts | 4 +-- 17 files changed, 103 insertions(+), 67 deletions(-) create mode 100644 lib/entity/fields/entity-binary-field.ts delete mode 100644 lib/entity/fields/entity-vector-field.ts rename lib/schema/definition/{vector-field-definition.ts => binary-field-definition.ts} (86%) rename spec/unit/schema/{vector-hash-fields.spec.ts => binary-hash-fields.spec.ts} (83%) rename spec/unit/schema/{vector-json-fields.spec.ts => binary-json-fields.spec.ts} (84%) diff --git a/lib/entity/entity.ts b/lib/entity/entity.ts index d31b71c6..299b51f3 100644 --- a/lib/entity/entity.ts +++ b/lib/entity/entity.ts @@ -8,7 +8,7 @@ import { EntityStringArrayField, EntityStringField, EntityTextField, - EntityVectorField, + EntityBinaryField, EntityFieldConstructor, } from "./fields"; import { Schema } from "../schema/schema"; @@ -23,7 +23,7 @@ const ENTITY_FIELD_CONSTRUCTORS: Record 'date': EntityDateField, 'point': EntityPointField, 'string[]': EntityStringArrayField, - 'vector': EntityVectorField, + 'binary': EntityBinaryField, } /** diff --git a/lib/entity/fields/entity-binary-field.ts b/lib/entity/fields/entity-binary-field.ts new file mode 100644 index 00000000..b6c0eee2 --- /dev/null +++ b/lib/entity/fields/entity-binary-field.ts @@ -0,0 +1,28 @@ +import { EntityField } from "./entity-field"; +import { RedisHashData, RedisJsonData } from "../../client"; + +export class EntityBinaryField extends EntityField { + toRedisJson(): RedisJsonData { + const data: RedisJsonData = {}; + if (this.value !== null) data[this.name] = this.valueAsBuffer.toString('base64') + return data; + } + + fromRedisJson(value: any) { + if (value === null) this.value = Buffer.from(value, 'base64'); + } + + toRedisHash(): RedisHashData { + const data: RedisHashData = {}; + if (this.value !== null) data[this.name] = this.valueAsBuffer + return data; + } + + fromRedisHash(value: string | Buffer) { + this.value = Buffer.from(value.toString(), 'binary'); + } + + private get valueAsBuffer(): Buffer { + return this.value as Buffer + } +} diff --git a/lib/entity/fields/entity-vector-field.ts b/lib/entity/fields/entity-vector-field.ts deleted file mode 100644 index 2b3bb529..00000000 --- a/lib/entity/fields/entity-vector-field.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { EntityField } from "./entity-field"; -import { RedisHashData, RedisJsonData } from "../../client"; - -export class EntityVectorField extends EntityField { - toRedisJson(): RedisJsonData { - throw Error(`Vector field not supported for JSON`); - } - - fromRedisJson(value: any) { - throw Error(`Vector field not supported for JSON`); - } - - toRedisHash(): RedisHashData { - const data: RedisHashData = {}; - if (this.value !== null) data[this.name] = this.value as Buffer - return data; - } - - fromRedisHash(value: string | Buffer) { - this.value = Buffer.from(value.toString(), 'binary'); - } -} diff --git a/lib/entity/fields/index.ts b/lib/entity/fields/index.ts index 021ca2e8..0a6a6751 100644 --- a/lib/entity/fields/index.ts +++ b/lib/entity/fields/index.ts @@ -1,3 +1,4 @@ +export * from './entity-binary-field' export * from './entity-boolean-field' export * from './entity-date-field' export * from './entity-field-constructor' @@ -7,5 +8,4 @@ export * from './entity-point-field' export * from './entity-string-array-field' export * from './entity-string-field' export * from './entity-stringish-field' -export * from './entity-text-field' -export * from './entity-vector-field' \ No newline at end of file +export * from './entity-text-field' \ No newline at end of file diff --git a/lib/schema/builders/hash-schema-builder.ts b/lib/schema/builders/hash-schema-builder.ts index 86384e77..a6b75edd 100644 --- a/lib/schema/builders/hash-schema-builder.ts +++ b/lib/schema/builders/hash-schema-builder.ts @@ -52,7 +52,7 @@ export class HashSchemaBuilder extends SchemaBuilder extends SchemaBuilder { return field.weight ? ['WEIGHT', field.weight.toString()] : [] } - protected buildVector(field: VectorFieldDefinition) { + protected buildVector(field: BinaryFieldDefinition) { // assume that indexed: false takes precedence - if (!(field.indexed ?? this.schema.indexedDefault)) { + if (!(field.indexed ?? this.schema.indexedDefault) || !field.vector) { return ['NOINDEX'] } diff --git a/lib/schema/definition/vector-field-definition.ts b/lib/schema/definition/binary-field-definition.ts similarity index 86% rename from lib/schema/definition/vector-field-definition.ts rename to lib/schema/definition/binary-field-definition.ts index a9b1b061..35ee6118 100644 --- a/lib/schema/definition/vector-field-definition.ts +++ b/lib/schema/definition/binary-field-definition.ts @@ -42,11 +42,11 @@ interface HNSWVectorParameters extends VectorParameters { type VectorAlgorithm = FlatVectorParameters | HNSWVectorParameters -/** A field representing vector similarity. */ -export interface VectorFieldDefinition extends BaseFieldDefinition { - /** Yep. It's a vector. */ - type: 'vector'; +/** A field representing binary data. */ +export interface BinaryFieldDefinition extends BaseFieldDefinition { + /** Yep. It's a binary. */ + type: 'binary'; // vector parameters - vector: VectorAlgorithm; + vector?: VectorAlgorithm; } diff --git a/lib/schema/definition/field-definition.ts b/lib/schema/definition/field-definition.ts index abbf475d..e2c637a0 100644 --- a/lib/schema/definition/field-definition.ts +++ b/lib/schema/definition/field-definition.ts @@ -5,7 +5,7 @@ import { PointFieldDefinition } from "./point-field-definition"; import { StringArrayFieldDefinition } from "./string-array-field-definition"; import { StringFieldDefinition } from "./string-field-definition"; import { TextFieldDefinition } from "./text-field-definition"; -import { VectorFieldDefinition } from "./vector-field-definition"; +import { BinaryFieldDefinition } from "./binary-field-definition"; /** Contains instructions telling how to map a property on an {@link Entity} to Redis. */ -export type FieldDefinition = StringFieldDefinition | TextFieldDefinition | NumberFieldDefinition | BooleanFieldDefinition | PointFieldDefinition | DateFieldDefinition | StringArrayFieldDefinition | VectorFieldDefinition; +export type FieldDefinition = StringFieldDefinition | TextFieldDefinition | NumberFieldDefinition | BooleanFieldDefinition | PointFieldDefinition | DateFieldDefinition | StringArrayFieldDefinition | BinaryFieldDefinition; diff --git a/lib/schema/definition/index.ts b/lib/schema/definition/index.ts index 0abdfc9e..21ef2f3c 100644 --- a/lib/schema/definition/index.ts +++ b/lib/schema/definition/index.ts @@ -1,4 +1,5 @@ export * from './base-field-definition' +export * from './binary-field-definition' export * from './boolean-field-definition' export * from './casesensitive-field-definition' export * from './date-field-definition' @@ -15,5 +16,4 @@ export * from './stemming-field-definition' export * from './string-array-field-definition' export * from './string-field-definition' export * from './text-field-definition' -export * from './vector-field-definition' export * from './weight-field-definition' \ No newline at end of file diff --git a/lib/schema/definition/schema-field-type.ts b/lib/schema/definition/schema-field-type.ts index 5b695b80..6476f909 100644 --- a/lib/schema/definition/schema-field-type.ts +++ b/lib/schema/definition/schema-field-type.ts @@ -1,4 +1,4 @@ /** * Valid types a {@link FieldDefinition}. */ -export type SchemaFieldType = 'string' | 'number' | 'boolean' | 'text' | 'date' | 'point' | 'string[]' | 'vector'; +export type SchemaFieldType = 'string' | 'number' | 'boolean' | 'text' | 'date' | 'point' | 'string[]' | 'binary'; diff --git a/lib/schema/schema.ts b/lib/schema/schema.ts index ada703cd..3b821cdb 100644 --- a/lib/schema/schema.ts +++ b/lib/schema/schema.ts @@ -163,7 +163,8 @@ export class Schema { } private validateFieldDef(field: string, fieldDef: FieldDefinition) { - if (!['boolean', 'date', 'number', 'point', 'string', 'string[]', 'text', 'vector'].includes(fieldDef.type)) - throw Error(`The field '${field}' is configured with a type of '${fieldDef.type}'. Valid types include 'boolean', 'date', 'number', 'point', 'string', 'string[]', and 'text'.`); + const fieldTypes = ['boolean', 'date', 'number', 'point', 'string', 'string[]', 'text', 'binary'] + if (!fieldTypes.includes(fieldDef.type)) + throw Error(`The field '${field}' is configured with a type of '${fieldDef.type}'. Valid types include ${fieldTypes.map(type => `'${type}'`).join(', ')}.`); } } diff --git a/lib/search/search.ts b/lib/search/search.ts index 233b4fc7..098e2073 100644 --- a/lib/search/search.ts +++ b/lib/search/search.ts @@ -619,7 +619,8 @@ export class Search extends AbstractSearch { if (fieldDef.type === 'string') return new WhereString(this, field); if (fieldDef.type === 'string[]') return new WhereStringArray(this, field); + // TODO: use single definition of valid field types as per lib/schema.ts // @ts-ignore: This is a trap for JavaScript - throw new Error(`The field type of '${fieldDef.type}' is not a valid field type. Valid types include 'boolean', 'date', 'number', 'point', 'string', and 'string[]'.`); + throw new Error(`The field type of '${fieldDef.type}' is not a valid field type. Valid types include 'boolean', 'date', 'number', 'point', 'string', 'string[]', 'text', 'binary'.`); } } diff --git a/spec/functional/vector.spec.ts b/spec/functional/vector.spec.ts index 05bf8d20..acff1abf 100644 --- a/spec/functional/vector.spec.ts +++ b/spec/functional/vector.spec.ts @@ -31,7 +31,7 @@ describe("Vector", () => { Product, { name: { type: 'text' }, price: { type: 'number' }, - image: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', initial_cap: 5, block_size: 5 }} + image: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', initial_cap: 5, block_size: 5 }} }, { dataStructure: 'HASH', }); @@ -54,14 +54,29 @@ describe("Vector", () => { entityIDs.push(entityID) } - // TODO: execute a raw search for the first product image and we should get the first 2 products back + // TODO: figure out rawSearch / where query encoding is happening ... - await repository.dropIndex(); + // execute a raw search for the first product image ... + const results = await redis.sendCommand([ + 'FT.SEARCH', 'Product:index', '*=>[KNN 2 @image $query_vector]', 'PARAMS', '2', + 'query_vector', Buffer.from(products[0].image, 'hex'), + 'RETURN', '3', '__image_score name price', + 'SORTBY', '__image_score', + 'DIALECT', '2' + ]) + + // ... and we should get the first 2 products back in order + expect(results).toStrictEqual([ 2, + 'Product:' + entityIDs[0], [ '__image_score', '-1.19209289551e-07' ], + 'Product:' + entityIDs[1], [ '__image_score', '0.212629973888' ], + ]) for (const entityID of entityIDs) { await repository.remove(entityID) } + await repository.dropIndex(); + // close the client await client.close() }); diff --git a/spec/unit/schema/vector-hash-fields.spec.ts b/spec/unit/schema/binary-hash-fields.spec.ts similarity index 83% rename from spec/unit/schema/vector-hash-fields.spec.ts rename to spec/unit/schema/binary-hash-fields.spec.ts index ad215df4..db848ec0 100644 --- a/spec/unit/schema/vector-hash-fields.spec.ts +++ b/spec/unit/schema/binary-hash-fields.spec.ts @@ -6,8 +6,16 @@ import { DataStructure } from '$lib/schema/options'; describe("Schema", () => { describe.each([ + ["that defines an unindexed binary", { + schemaDef: { aField: { type: 'binary' } } as SchemaDefinition, + dataStructure: 'HASH', + expectedRedisSchema: [ + 'aField', 'NOINDEX' + ] + }], + ["that defines a FLAT / 512 / COSINE vector for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' @@ -15,7 +23,7 @@ describe("Schema", () => { }], ["that defines a FLAT / 256 / IP vector for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'FLAT', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' @@ -23,7 +31,7 @@ describe("Schema", () => { }], ["that defines a FLAT / 1024 / L2 vector for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'FLAT', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' @@ -31,7 +39,7 @@ describe("Schema", () => { }], ["that defines a FLAT / 512 / COSINE vector with block_size for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', block_size: 512*512 } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', block_size: 512*512 } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'FLAT', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'BLOCK_SIZE', '262144' @@ -39,7 +47,7 @@ describe("Schema", () => { }], ["that defines an aliased FLAT / 512 / COSINE vector for a HASH", { - schemaDef: { aField: { type: 'vector', alias: 'anotherField', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', alias: 'anotherField', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'anotherField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' @@ -49,7 +57,7 @@ describe("Schema", () => { // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence ["that defines an unindexed FLAT vector for a HASH", { - schemaDef: { aField: { type: 'vector', indexed: false, vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', indexed: false, vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'NOINDEX' @@ -57,7 +65,7 @@ describe("Schema", () => { }], ["that defines a HNSW / 512 / COSINE vector for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' @@ -65,7 +73,7 @@ describe("Schema", () => { }], ["that defines a HNSW / 256 / IP vector for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' @@ -73,7 +81,7 @@ describe("Schema", () => { }], ["that defines a HNSW / 1024 / L2 vector for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' @@ -81,7 +89,7 @@ describe("Schema", () => { }], ["that defines a HNSW / 512 / COSINE vector with M for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', m: 8 } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', m: 8 } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'M', '8' @@ -89,7 +97,7 @@ describe("Schema", () => { }], ["that defines a HNSW / 512 / COSINE vector with EF_CONSTRUCTION for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_construction: 250 } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_construction: 250 } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_CONSTRUCTION', '250' @@ -97,7 +105,7 @@ describe("Schema", () => { }], ["that defines a HNSW / 512 / COSINE vector with EF_RUNTIME for a HASH", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_runtime: 20 } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_runtime: 20 } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_RUNTIME', '20' @@ -105,7 +113,7 @@ describe("Schema", () => { }], ["that defines an aliased HNSW / 512 / COSINE vector for a HASH", { - schemaDef: { aField: { type: 'vector', alias: 'anotherField', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', alias: 'anotherField', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'anotherField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' @@ -115,7 +123,7 @@ describe("Schema", () => { // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence ["that defines an unindexed HNSW vector for a HASH", { - schemaDef: { aField: { type: 'vector', indexed: false, vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + schemaDef: { aField: { type: 'binary', indexed: false, vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, dataStructure: 'HASH', expectedRedisSchema: [ 'aField', 'NOINDEX' diff --git a/spec/unit/schema/vector-json-fields.spec.ts b/spec/unit/schema/binary-json-fields.spec.ts similarity index 84% rename from spec/unit/schema/vector-json-fields.spec.ts rename to spec/unit/schema/binary-json-fields.spec.ts index fa140e7d..d39ae483 100644 --- a/spec/unit/schema/vector-json-fields.spec.ts +++ b/spec/unit/schema/binary-json-fields.spec.ts @@ -8,10 +8,12 @@ const warnSpy = vi.spyOn(global.console, 'warn').mockImplementation(() => {}) describe("Schema", () => { describe.each([ - ["that defines a vector for a JSON", { - schemaDef: { aField: { type: 'vector', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + ["that defines a binary for a JSON", { + schemaDef: { aField: { type: 'binary' } } as SchemaDefinition, dataStructure: 'JSON', - expectedRedisSchema: [], + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'NOINDEX' + ], expectedWarning: null }], diff --git a/spec/unit/schema/schema.spec.ts b/spec/unit/schema/schema.spec.ts index d63c497b..d5742511 100644 --- a/spec/unit/schema/schema.spec.ts +++ b/spec/unit/schema/schema.spec.ts @@ -154,12 +154,12 @@ describe("Schema", () => { it("throws an exception when the type is missing on a field definition", () => // @ts-ignore: JavaScript test expect(() => new Schema(TestEntity, { aField: {} })) - .toThrow("The field 'aField' is configured with a type of 'undefined'. Valid types include 'boolean', 'date', 'number', 'point', 'string', 'string[]', and 'text'.")); + .toThrow("The field 'aField' is configured with a type of 'undefined'. Valid types include 'boolean', 'date', 'number', 'point', 'string', 'string[]', 'text', 'binary'.")); it("throws an exception when the type is invalid on a field definition", () => // @ts-ignore: JavaScript test expect(() => new Schema(TestEntity, { aField: { type: 'foo' } })) - .toThrow("The field 'aField' is configured with a type of 'foo'. Valid types include 'boolean', 'date', 'number', 'point', 'string', 'string[]', and 'text'.")); + .toThrow("The field 'aField' is configured with a type of 'foo'. Valid types include 'boolean', 'date', 'number', 'point', 'string', 'string[]', 'text', 'binary'.")); it("throws an exception when the data structure is invalid", () => { // @ts-ignore: JavaScript test From 143ef47393dc7e9fbb48e392be54bebf7502638f Mon Sep 17 00:00:00 2001 From: Simon Green Date: Fri, 1 Jul 2022 14:02:36 -0600 Subject: [PATCH 09/28] Refactor test to cleanup in case of failure --- spec/functional/vector.spec.ts | 60 ++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/spec/functional/vector.spec.ts b/spec/functional/vector.spec.ts index acff1abf..5b1555d9 100644 --- a/spec/functional/vector.spec.ts +++ b/spec/functional/vector.spec.ts @@ -4,29 +4,49 @@ import { Client } from '$lib/client'; import { Schema } from '$lib/schema/schema'; import { Entity } from '$lib/entity/entity'; import { Repository } from '$lib/repository'; +import { removeAll } from './helpers/redis-helper'; describe("Vector", () => { - - it("demo", async () => { + let redis: ReturnType + let client: Client + let repository: Repository + let entityIDs: string[] + + // define the interface, just for TypeScript + interface Product { + name: string; + price: number; + image: Buffer; + } + + // define the entity class and add any business logic to it + class Product extends Entity { + } + + beforeAll(async () => { // establish an existing connection to Redis - let redis = createClient(); + redis = createClient(); redis.on('error', (err) => console.log('Redis Client Error', err)); await redis.connect(); - // define the interface, just for TypeScript - interface Product { - name: string; - price: number; - image: Buffer; - } + // get a client use an existing Redis connection + client = await new Client().use(redis); - // define the entity class and add any business logic to it - class Product extends Entity { - } + await removeAll(client, 'Product:') - // get a client use an existing Redis connection - let client = await new Client().use(redis); + entityIDs = [] + }) + + afterAll(async () => { + await removeAll(client, 'Product:') + + await repository.dropIndex(); + + // close the client + await client.close() + }) + it("demo", async () => { let schema = new Schema( Product, { name: { type: 'text' }, @@ -36,7 +56,7 @@ describe("Vector", () => { dataStructure: 'HASH', }); - let repository: Repository = client.fetchRepository(schema); + repository = client.fetchRepository(schema); await repository.createIndex(); @@ -48,7 +68,6 @@ describe("Vector", () => { return await repository.save(entity); } - const entityIDs = [] for (const product of products) { const entityID = await loadProduct(product) entityIDs.push(entityID) @@ -70,15 +89,6 @@ describe("Vector", () => { 'Product:' + entityIDs[0], [ '__image_score', '-1.19209289551e-07' ], 'Product:' + entityIDs[1], [ '__image_score', '0.212629973888' ], ]) - - for (const entityID of entityIDs) { - await repository.remove(entityID) - } - - await repository.dropIndex(); - - // close the client - await client.close() }); }); From f340570c28bf7df766ebdd0dd586ba008ec0036b Mon Sep 17 00:00:00 2001 From: Simon Green Date: Sat, 2 Jul 2022 11:34:36 -0600 Subject: [PATCH 10/28] Describe binary \ vector in readme --- README.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1b192004..9ca86c86 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,7 @@ const studioSchema = new Schema(Studio, { }) ``` -When you create a `Schema`, it modifies the entity you handed it, adding getters and setters for the properties you define. The type those getters and setters accept and return are defined with the type parameter above. Valid values are: `string`, `number`, `boolean`, `string[]`, `date`, `point`, or `text`. +When you create a `Schema`, it modifies the entity you handed it, adding getters and setters for the properties you define. The type those getters and setters accept and return are defined with the type parameter above. Valid values are: `string`, `number`, `boolean`, `string[]`, `date`, `point`, `text` or `binary`. The first three do exactly what you think—they define a property that is a [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), a [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), or a [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean). `string[]` does what you'd think as well, specifically defining an [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) of Strings. @@ -236,17 +236,20 @@ const point = { longitude: 12.34, latitude: 56.78 } A `text` field is a lot like a `string`. If you're just reading and writing objects, they are identical. But if you want to *search* on them, they are very, very different. I'll cover that in detail when I talk about [using RediSearch](#-using-redisearch) but the tl;dr is that `string` fields can only be matched on their whole value—no partial matches—and are best for keys while `text` fields have full-text search enabled on them and are optimized for human-readable text. -Additional field options can be set depending on the field type. These correspond to the [Field Options](https://redis.io/commands/ft.create/#field-options) available when creating a RediSearch full-text index. Other than the `separator` option, these only affect how content is indexed and searched. +A `binary` field is a binary blob of data using a `Buffer` object. For Hash data structures it will be stored as a binary field in Redis, for JSON data structures it will be serialized to a Base64 string. The `binary` field stored in a Hash data structure can be indexed as a [Vector Similarity](https://redis.io/docs/stack/search/reference/vectors/) field. When stored in a JSON data structure it will be automatically unindexed. -| schema type | RediSearch type | `indexed` | `sortable` | `normalized` | `stemming` | `phonetic` | `weight` | `separator` | `caseSensitive` | -| -------------- | :-------------: | :-------: | :--------: | :----------: | :--------: | :--------: | :------: | :---------: | :-------------: | -| `string` | TAG | yes | HASH Only | HASH Only | - | - | - | yes | yes | -| `number` | NUMERIC | yes | yes | - | - | - | - | - | - | -| `boolean` | TAG | yes | HASH Only | - | - | - | - | - | - | -| `string[]` | TAG | yes | HASH Only | HASH Only | - | - | - | yes | yes | -| `date` | NUMERIC | yes | yes | - | | - | - | - | - | -| `point` | GEO | yes | - | - | | - | - | - | - | -| `text` | TEXT | yes | yes | yes | yes | yes | yes | - | - | +Additional field options can be set depending on the field type. These correspond to the [Field Options](https://redis.io/commands/ft.create/#field-options) avialable when creating a RediSearch full-text index. Other than the `separator` option, these only affect how content is indexed and searched. + +| schema type | RediSearch type | `indexed` | `sortable` | `normalized` | `stemming` | `phonetic` | `weight` | `separator` | `caseSensitive` | `vector` | +| -------------- | :-------------: | :-------: | :--------: | :----------: | :--------: | :--------: | :------: | :---------: | :-------------: | :------: | +| `string` | TAG | yes | HASH Only | HASH Only | - | - | - | yes | yes | - | +| `number` | NUMERIC | yes | yes | - | - | - | - | - | - | - | +| `boolean` | TAG | yes | HASH Only | - | - | - | - | - | - | - | +| `string[]` | TAG | yes | HASH Only | HASH Only | - | - | - | yes | yes | - | +| `date` | NUMERIC | yes | yes | - | - | - | - | - | - | - | +| `point` | GEO | yes | - | - | - | - | - | - | - | - | +| `text` | TEXT | yes | yes | yes | yes | yes | yes | - | - | - | +| `binary` | VECTOR | yes | - | - | - | - | - | - | - | yes | * `indexed`: true | false, whether this field is indexed by RediSearch (default true) * `sortable`: true | false, whether to create an additional index to optmize sorting (default false) @@ -256,6 +259,7 @@ Additional field options can be set depending on the field type. These correspon * `weight`: number, the importance weighting to use when ranking results (default 1) * `separator`: string, the character to delimit multiple tags (default '|') * `caseSensitive`: true | false, whether original letter casing is kept for search (default false) +* `vector`: object containing [Vector Similarity](https://redis.io/docs/stack/search/reference/vectors/) configuration Example showing additional options: @@ -269,6 +273,7 @@ const commentSchema = new Schema(Comment, { approved: { type: 'boolean', indexed: false }, iphash: { type: 'string', caseSensitive: true }, notes: { type: 'string', indexed: false }, + image: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } }, }) ``` From 00f08d4a1ef83a93462b1d19108142085695cc2e Mon Sep 17 00:00:00 2001 From: Simon Green Date: Sat, 2 Jul 2022 11:46:01 -0600 Subject: [PATCH 11/28] Kick CI build Why suddenly failing? --- .github/workflows/ci.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0da1e7f4..37b1ac14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,17 +26,13 @@ jobs: --health-retries 5 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2.3.0 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - - name: Cache dependencies - uses: c-hive/gha-npm-cache@v1 - - - name: Update npm - run: npm install --global npm + cache: 'npm' - name: Install packages run: npm ci From 9bdbe30a3576cfde794f23cf595df6f9e467f48e Mon Sep 17 00:00:00 2001 From: Simon Green Date: Sat, 2 Jul 2022 11:49:48 -0600 Subject: [PATCH 12/28] Try without node 14 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37b1ac14..d7390f31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14, 16, 18] + node-version: [16, 18] services: redis: image: redis/redis-stack-server:latest From bc52b648770a82ef6bb1ae809dd700a8b29088a4 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Sat, 2 Jul 2022 12:06:10 -0600 Subject: [PATCH 13/28] Make vector result check less strict --- spec/functional/vector.spec.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/spec/functional/vector.spec.ts b/spec/functional/vector.spec.ts index 5b1555d9..5fa743f7 100644 --- a/spec/functional/vector.spec.ts +++ b/spec/functional/vector.spec.ts @@ -82,13 +82,16 @@ describe("Vector", () => { 'RETURN', '3', '__image_score name price', 'SORTBY', '__image_score', 'DIALECT', '2' - ]) + ]) as any[] // ... and we should get the first 2 products back in order - expect(results).toStrictEqual([ 2, - 'Product:' + entityIDs[0], [ '__image_score', '-1.19209289551e-07' ], - 'Product:' + entityIDs[1], [ '__image_score', '0.212629973888' ], - ]) + expect(results).toBeDefined() + expect(results).toBeInstanceOf(Array) + expect(results.length).toBe(5) + expect(results[1]).toBe('Product:' + entityIDs[0]) + expect(parseFloat(results[2][1])).toBeLessThan(1e-4) + expect(results[3]).toBe('Product:' + entityIDs[1]) + expect(parseFloat(results[4][1])).toBeGreaterThan(0.2) }); }); From 7b80089c8088a0fe63c44e8f51c83f9a0edf4211 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Sat, 2 Jul 2022 12:59:14 -0600 Subject: [PATCH 14/28] Revert "Try without node 14" This reverts commit 89cf8bde176cb79a66f5407b3263e0f8bb395957. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7390f31..37b1ac14 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16, 18] + node-version: [14, 16, 18] services: redis: image: redis/redis-stack-server:latest From 17ea3462a15d0fd8eae144e1cd220d511d41fdb9 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Mon, 4 Jul 2022 14:07:21 -0600 Subject: [PATCH 15/28] Return buffers from Redis for HASH structures --- lib/client.ts | 4 ++-- lib/entity/entity-value.ts | 2 +- spec/unit/client/client-hgetall.spec.ts | 4 ++-- spec/unit/helpers/mock-redis.ts | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/client.ts b/lib/client.ts index bb5c2414..50407c7b 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -1,4 +1,4 @@ -import { createClient } from 'redis'; +import { createClient, commandOptions } from 'redis'; import { Repository } from './repository'; import { JsonRepository, HashRepository } from './repository'; import { Entity } from './entity/entity'; @@ -204,7 +204,7 @@ export class Client { /** @internal */ async hgetall(key: string): Promise { this.validateRedisOpen(); - return this.redis.hGetAll(key); + return this.redis.hGetAll(commandOptions({ returnBuffers: true }), key); } /** @internal */ diff --git a/lib/entity/entity-value.ts b/lib/entity/entity-value.ts index 86bc9f01..3f753a01 100644 --- a/lib/entity/entity-value.ts +++ b/lib/entity/entity-value.ts @@ -3,4 +3,4 @@ import { Point } from "./point"; /** * Valid types for properties on an {@link Entity}. */ -export type EntityValue = string | number | boolean | Point | Date | any[] | ArrayBuffer | null; +export type EntityValue = string | number | boolean | Point | Date | any[] | Buffer | null; diff --git a/spec/unit/client/client-hgetall.spec.ts b/spec/unit/client/client-hgetall.spec.ts index dc5b2a90..a266d02b 100644 --- a/spec/unit/client/client-hgetall.spec.ts +++ b/spec/unit/client/client-hgetall.spec.ts @@ -1,4 +1,4 @@ -import { redis } from '../helpers/mock-redis' +import { redis, commandOptions } from '../helpers/mock-redis' import { Client, RedisHashData } from '$lib/client'; @@ -20,7 +20,7 @@ describe("Client", () => { }); it("passes the command to redis", async () => { - expect(redis.hGetAll).toHaveBeenCalledWith('foo'); + expect(redis.hGetAll).toHaveBeenCalledWith(commandOptions({ returnBuffers: true }), 'foo'); }); it("returns the value from redis", async () => { diff --git a/spec/unit/helpers/mock-redis.ts b/spec/unit/helpers/mock-redis.ts index a4124ffb..8564cf04 100644 --- a/spec/unit/helpers/mock-redis.ts +++ b/spec/unit/helpers/mock-redis.ts @@ -13,5 +13,6 @@ export const redis = { } export const createClient = vi.fn(() => redis) +export const commandOptions = vi.fn() -vi.mock('redis', () => ({ createClient })) \ No newline at end of file +vi.mock('redis', () => ({ createClient, commandOptions })) \ No newline at end of file From 0e7c340320391fab8bbec22c33095de21a9c6d35 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Mon, 4 Jul 2022 14:08:41 -0600 Subject: [PATCH 16/28] Handle string or Buffer passed to fromRedisHash --- lib/entity/fields/entity-binary-field.ts | 14 ++++++++++++-- lib/entity/fields/entity-boolean-field.ts | 7 ++++--- lib/entity/fields/entity-date-field.ts | 4 ++-- lib/entity/fields/entity-field.ts | 6 +++++- lib/entity/fields/entity-number-field.ts | 4 ++-- lib/entity/fields/entity-point-field.ts | 7 ++++--- lib/entity/fields/entity-string-array-field.ts | 4 ++-- 7 files changed, 31 insertions(+), 15 deletions(-) diff --git a/lib/entity/fields/entity-binary-field.ts b/lib/entity/fields/entity-binary-field.ts index b6c0eee2..17a8fe42 100644 --- a/lib/entity/fields/entity-binary-field.ts +++ b/lib/entity/fields/entity-binary-field.ts @@ -1,5 +1,6 @@ import { EntityField } from "./entity-field"; import { RedisHashData, RedisJsonData } from "../../client"; +import { EntityValue } from "../entity-value"; export class EntityBinaryField extends EntityField { toRedisJson(): RedisJsonData { @@ -9,7 +10,7 @@ export class EntityBinaryField extends EntityField { } fromRedisJson(value: any) { - if (value === null) this.value = Buffer.from(value, 'base64'); + if (value !== null) this.value = Buffer.from(value, 'base64'); } toRedisHash(): RedisHashData { @@ -19,7 +20,16 @@ export class EntityBinaryField extends EntityField { } fromRedisHash(value: string | Buffer) { - this.value = Buffer.from(value.toString(), 'binary'); + if (!this.isBuffer(value)) { + throw Error(`Non-binary value of '${value}' read from Redis for binary field.`) + } + this.value = value as Buffer + } + + protected validateValue(value: EntityValue) { + super.validateValue(value); + if (value !== null && !this.isBuffer(value)) + throw Error(`Expected value with type of 'binary' but received '${value}'.`); } private get valueAsBuffer(): Buffer { diff --git a/lib/entity/fields/entity-boolean-field.ts b/lib/entity/fields/entity-boolean-field.ts index 16eaa387..0910f3e2 100644 --- a/lib/entity/fields/entity-boolean-field.ts +++ b/lib/entity/fields/entity-boolean-field.ts @@ -9,10 +9,11 @@ export class EntityBooleanField extends EntityField { return data; }; - fromRedisHash(value: string) { - if (value === '0') { + fromRedisHash(value: string | Buffer) { + const str = value.toString() + if (str === '0') { this.value = false; - } else if (value === '1') { + } else if (str === '1') { this.value = true; } else { throw Error(`Non-boolean value of '${value}' read from Redis for boolean field.`); diff --git a/lib/entity/fields/entity-date-field.ts b/lib/entity/fields/entity-date-field.ts index 931ba906..4459ef30 100644 --- a/lib/entity/fields/entity-date-field.ts +++ b/lib/entity/fields/entity-date-field.ts @@ -20,8 +20,8 @@ export class EntityDateField extends EntityField { return data; } - fromRedisHash(value: string) { - const parsed = Number.parseFloat(value); + fromRedisHash(value: string | Buffer) { + const parsed = Number.parseFloat(value.toString()); if (Number.isNaN(parsed)) throw Error(`Non-numeric value of '${value}' read from Redis for date field.`); const date = new Date(); date.setTime(parsed * 1000); diff --git a/lib/entity/fields/entity-field.ts b/lib/entity/fields/entity-field.ts index cc30d59a..9c0b0f88 100644 --- a/lib/entity/fields/entity-field.ts +++ b/lib/entity/fields/entity-field.ts @@ -45,7 +45,7 @@ export abstract class EntityField { } fromRedisHash(value: string | Buffer) { - this.value = value; + this.value = value.toString(); } protected validateValue(value: EntityValue) { @@ -67,4 +67,8 @@ export abstract class EntityField { protected isBoolean(value: EntityValue) { return typeof value === 'boolean'; } + + protected isBuffer(value: EntityValue) { + return value instanceof Buffer; + } } diff --git a/lib/entity/fields/entity-number-field.ts b/lib/entity/fields/entity-number-field.ts index 548afe33..2f688e34 100644 --- a/lib/entity/fields/entity-number-field.ts +++ b/lib/entity/fields/entity-number-field.ts @@ -2,8 +2,8 @@ import { EntityField } from "./entity-field"; import { EntityValue } from "../entity-value"; export class EntityNumberField extends EntityField { - fromRedisHash(value: string) { - const number = Number.parseFloat(value); + fromRedisHash(value: string | Buffer) { + const number = Number.parseFloat(value.toString()); if (Number.isNaN(number)) throw Error(`Non-numeric value of '${value}' read from Redis for number field.`); this.value = number; } diff --git a/lib/entity/fields/entity-point-field.ts b/lib/entity/fields/entity-point-field.ts index a4d3f272..96b54cf9 100644 --- a/lib/entity/fields/entity-point-field.ts +++ b/lib/entity/fields/entity-point-field.ts @@ -29,9 +29,10 @@ export class EntityPointField extends EntityField { return data; }; - fromRedisHash(value: string) { - if (value.match(IS_COORD_PAIR)) { - const [longitude, latitude] = value.split(',').map(Number.parseFloat); + fromRedisHash(value: string | Buffer) { + const str = value.toString() + if (str.match(IS_COORD_PAIR)) { + const [longitude, latitude] = str.split(',').map(Number.parseFloat); this.value = { longitude, latitude }; } else { throw Error(`Non-point value of '${value}' read from Redis for point field.`); diff --git a/lib/entity/fields/entity-string-array-field.ts b/lib/entity/fields/entity-string-array-field.ts index eeb6a22a..e2d6f9ee 100644 --- a/lib/entity/fields/entity-string-array-field.ts +++ b/lib/entity/fields/entity-string-array-field.ts @@ -10,8 +10,8 @@ export class EntityStringArrayField extends EntityField { return data; } - fromRedisHash(value: string) { - this.value = value.split(this.separator); + fromRedisHash(value: string | Buffer) { + this.value = value.toString().split(this.separator); } protected validateValue(value: EntityValue) { From ce04c792006314a2acfce4da84d4deec831c077c Mon Sep 17 00:00:00 2001 From: Simon Green Date: Mon, 4 Jul 2022 14:09:03 -0600 Subject: [PATCH 17/28] Test for entity binary field encoding / decoding --- spec/helpers/example-data.ts | 3 + spec/unit/entity/entity-binary-field.spec.ts | 175 +++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 spec/unit/entity/entity-binary-field.spec.ts diff --git a/spec/helpers/example-data.ts b/spec/helpers/example-data.ts index 777b8403..23552149 100644 --- a/spec/helpers/example-data.ts +++ b/spec/helpers/example-data.ts @@ -59,6 +59,9 @@ export const SOME_MORE_STRINGS: Array = ['charlie', 'delta', 'echo']; export const SOME_MORE_STRINGS_JSON: string = JSON.stringify(SOME_MORE_STRINGS); export const SOME_MORE_STRINGS_JOINED: string = SOME_MORE_STRINGS.join('|'); +export const A_BUFFER = Buffer.from([1, 2, 3, 4, 5, 6]) +export const A_BUFFER_BASE64 = 'AQIDBAUG' + export type SampleEntityData = { aString: string | null; anotherString: string | null; diff --git a/spec/unit/entity/entity-binary-field.spec.ts b/spec/unit/entity/entity-binary-field.spec.ts new file mode 100644 index 00000000..abdd6f86 --- /dev/null +++ b/spec/unit/entity/entity-binary-field.spec.ts @@ -0,0 +1,175 @@ +import { FieldDefinition } from "../../../lib"; +import { EntityBinaryField } from "$lib/entity/fields"; +import { A_DATE, A_NUMBER, A_NUMBER_STRING, A_POINT, A_STRING, SOME_STRINGS, A_BUFFER, A_BUFFER_BASE64 } from "../../helpers/example-data"; + +const FIELD_NAME = 'foo'; +const FIELD_DEF: FieldDefinition = { type: 'binary' }; +const EXPECTED_NULL_JSON_DATA = {}; +const EXPECTED_NULL_HASH_DATA = {}; +const EXPECTED_JSON_DATA = { foo: A_BUFFER_BASE64 }; +const EXPECTED_HASH_DATA = { foo: A_BUFFER }; + +describe("EntityBinaryField", () => { + + let field: EntityBinaryField; + + describe("when created", () => { + + beforeEach(() => { + field = new EntityBinaryField(FIELD_NAME, FIELD_DEF) + }); + + it("has the expected alias", () => expect(field.name).toBe(FIELD_NAME)); + it("has a value of null", () => expect(field.value).toBeNull()); + it("converts to the expected Redis JSON data", () => expect(field.toRedisJson()).toEqual(EXPECTED_NULL_JSON_DATA)); + it("converts to the expected Redis Hash data", () => expect(field.toRedisHash()).toEqual(EXPECTED_NULL_HASH_DATA)); + + describe("when loaded from Redis JSON data", () => { + beforeEach(() => field.fromRedisJson(A_BUFFER_BASE64)); + it("has the expected value", () => expect(field.value).toEqual(A_BUFFER)); + }); + + describe("when loaded from Redis JSON data containing a null", () => { + beforeEach(() => field.fromRedisJson(null)); + it("has the expected value", () => expect(field.value).toBeNull()); + }); + + it("when loaded from Redis JSON data containing invalid base64", () => { + beforeEach(() => field.fromRedisJson('^~$')); + it("has has the null value", () => expect(field.value).toBeNull()); + }); + + describe("when loaded from Redis Hash data", () => { + beforeEach(() => field.fromRedisHash(A_BUFFER)); + it("has the expected value", () => expect(field.value).toEqual(A_BUFFER)); + }); + + it("complains when loaded from invalid Redis Hash data", () => { + // @ts-ignore: JavaScript trap + expect(() => field.fromRedisHash('foo')) + .toThrow("Non-binary value of 'foo' read from Redis for binary field."); + }); + + describe("when created with a buffer", () => { + beforeEach(() => { + field.value = A_BUFFER + }); + it("has the expected value", () => expect(field.value).toBe(A_BUFFER)); + it("converts to the expected Redis JSON data", () => expect(field.toRedisJson()).toEqual(EXPECTED_JSON_DATA)); + it("converts to the expected Redis Hash data", () => expect(field.toRedisHash()).toEqual(EXPECTED_HASH_DATA)); + }); + + describe("when created with a null", () => { + beforeEach(() => { + field.value = A_BUFFER; // set it to something else first + field.value = null; + }); + it("has the expected value", () => expect(field.value).toBeNull()); + it("converts to the expected Redis JSON data", () => expect(field.toRedisJson()).toEqual(EXPECTED_NULL_JSON_DATA)); + it("converts to the expected Redis Hash data", () => expect(field.toRedisHash()).toEqual(EXPECTED_NULL_HASH_DATA)); + }); + + it("cannot be set to undefined", () => { + // @ts-ignore: JavaScript trap + expect(() => field.value = undefined) + .toThrow("Property cannot be set to undefined. Use null instead."); + }); + + it("cannot be set to a string", () => { + // @ts-ignore: JavaScript trap + expect(() => field.value = A_STRING) + .toThrow(`Expected value with type of 'binary' but received '${A_STRING}'.`); + }); + + it("cannot be set to a boolean", () => { + // @ts-ignore: JavaScript trap + expect(() => field.value = true) + .toThrow(`Expected value with type of 'binary' but received 'true'.`); + }); + + it("cannot be set to a Number", () => { + // @ts-ignore: JavaScript trap + expect(() => field.value = A_NUMBER) + .toThrow(`Expected value with type of 'binary' but received '${A_NUMBER}'.`); + }); + + it("cannot be set to a Point", () => { + // @ts-ignore: JavaScript trap + expect(() => field.value = A_POINT) + .toThrow(`Expected value with type of 'binary' but received '${A_POINT}'.`); + }); + + it("cannot be set to a Date", () => { + // @ts-ignore: JavaScript trap + expect(() => field.value = A_DATE) + .toThrow(`Expected value with type of 'binary' but received '${A_DATE}'.`); + }); + + it("cannot be set to an array of strings", () => { + // @ts-ignore: JavaScript trap + expect(() => field.value = SOME_STRINGS) + .toThrow(`Expected value with type of 'binary' but received '${SOME_STRINGS}'.`); + }); + }); + + describe("when created with an alias", () => { + beforeEach(() => { + field = new EntityBinaryField(FIELD_NAME, { type: 'binary', alias: 'bar' }) + }); + it("has the aliased name", () => expect(field.name).toBe('bar')); + }); + + describe("when created with a buffer", () => { + beforeEach(() => { + field = new EntityBinaryField(FIELD_NAME, FIELD_DEF, A_BUFFER) + }); + it("has the expected value", () => expect(field.value).toBe(A_BUFFER)); + it("converts to the expected Redis JSON data", () => expect(field.toRedisJson()).toEqual(EXPECTED_JSON_DATA)); + it("converts to the expected Redis Hash data", () => expect(field.toRedisHash()).toEqual(EXPECTED_HASH_DATA)); + }); + + describe("when created with a null", () => { + beforeEach(() => { + field = new EntityBinaryField(FIELD_NAME, FIELD_DEF, null) + }); + it("has the expected value", () => expect(field.value).toBeNull()); + it("converts to the expected Redis JSON data", () => expect(field.toRedisJson()).toEqual(EXPECTED_NULL_JSON_DATA)); + it("converts to the expected Redis Hash data", () => expect(field.toRedisHash()).toEqual(EXPECTED_NULL_HASH_DATA)); + }); + + it("complains when created with a string", () => { + // @ts-ignore: JavaScript trap + expect(() => new EntityBinaryField(FIELD_NAME, FIELD_DEF, A_STRING)) + .toThrow(`Expected value with type of 'binary' but received '${A_STRING}'.`); + }); + + it("complains when created with a boolean", () => { + // @ts-ignore: JavaScript trap + expect(() => new EntityBinaryField(FIELD_NAME, FIELD_DEF, true)) + .toThrow(`Expected value with type of 'binary' but received 'true'.`); + }); + + it("complains when created with a Number", () => { + // @ts-ignore: JavaScript trap + expect(() => new EntityBinaryField(FIELD_NAME, FIELD_DEF, A_NUMBER)) + .toThrow(`Expected value with type of 'binary' but received '${A_NUMBER}'.`); + }); + + it("complains when created with a Point", () => { + // @ts-ignore: JavaScript trap + expect(() => new EntityBinaryField(FIELD_NAME, FIELD_DEF, A_POINT)) + .toThrow(`Expected value with type of 'binary' but received '${A_POINT}'.`); + }); + + it("complains when created with a Date", () => { + // @ts-ignore: JavaScript trap + expect(() => new EntityBinaryField(FIELD_NAME, FIELD_DEF, A_DATE)) + .toThrow(`Expected value with type of 'binary' but received '${A_DATE}'.`); + }); + + it("complains when created with an array of strings", () => { + // @ts-ignore: JavaScript trap + expect(() => new EntityBinaryField(FIELD_NAME, FIELD_DEF, SOME_STRINGS)) + .toThrow(`Expected value with type of 'binary' but received '${SOME_STRINGS}'.`); + }); +}); From c13f2b2d3d9144a0618d73cc3a50d2d9ee071415 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Mon, 4 Jul 2022 16:10:54 -0600 Subject: [PATCH 18/28] Need to return buffers from search as well --- lib/client.ts | 2 +- lib/search/results-converter.ts | 13 +++++++------ spec/unit/client/client-search.spec.ts | 26 +++++++++++++++++++------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/lib/client.ts b/lib/client.ts index 50407c7b..a84ec1b7 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -174,7 +174,7 @@ export class Client { if (keysOnly) command.push('RETURN', '0'); - return this.redis.sendCommand(command); + return this.redis.sendCommand(command, commandOptions({ returnBuffers: true })); } /** @internal */ diff --git a/lib/search/results-converter.ts b/lib/search/results-converter.ts index 14832d32..c7f4fb38 100644 --- a/lib/search/results-converter.ts +++ b/lib/search/results-converter.ts @@ -18,7 +18,7 @@ export abstract class SearchResultsConverter { } get ids(): Array { - return this.keys.map(key => (key as string).replace(/^.*:/, "")); + return this.keys.map(key => key.toString().replace(/^.*:/, "")); } get keys(): Array { @@ -42,12 +42,12 @@ export abstract class SearchResultsConverter { } export class HashSearchResultsConverter extends SearchResultsConverter { - protected arrayToEntity(id: string, array: Array): TEntity { + protected arrayToEntity(id: string, array: Array): TEntity { const keys = array.filter((_entry, index) => index % 2 === 0); const values = array.filter((_entry, index) => index % 2 !== 0); const hashData: RedisHashData = keys.reduce((object: any, key, index) => { - object[key] = values[index] + object[key.toString()] = values[index] return object }, {}); @@ -58,9 +58,10 @@ export class HashSearchResultsConverter extends SearchRe } export class JsonSearchResultsConverter extends SearchResultsConverter { - protected arrayToEntity(id: string, array: Array): TEntity { - const index = array.findIndex(value => value === '$') + 1; - const jsonString = array[index]; + protected arrayToEntity(id: string, array: Array): TEntity { + const items = array.map(item => item.toString()) + const index = items.findIndex(value => value === '$') + 1; + const jsonString = items[index]; const jsonData: RedisJsonData = JSON.parse(jsonString); const entity = new this.schema.entityCtor(this.schema, id); entity.fromRedisJson(jsonData); diff --git a/spec/unit/client/client-search.spec.ts b/spec/unit/client/client-search.spec.ts index da20aa6a..0b401d00 100644 --- a/spec/unit/client/client-search.spec.ts +++ b/spec/unit/client/client-search.spec.ts @@ -1,4 +1,4 @@ -import { redis } from '../helpers/mock-redis' +import { redis, commandOptions } from '../helpers/mock-redis' import { Client } from '$lib/client'; @@ -22,7 +22,9 @@ describe("Client", () => { query: 'query' }); expect(redis.sendCommand).toHaveBeenCalledWith([ - 'FT.SEARCH', 'index', 'query']); + 'FT.SEARCH', 'index', 'query'], + commandOptions({ returnBuffers: true }) + ); }); it("sends the expect command when given a limit", async () => { @@ -32,7 +34,9 @@ describe("Client", () => { limit: { offset: 0, count: 5 } }); expect(redis.sendCommand).toHaveBeenCalledWith([ - 'FT.SEARCH', 'index', 'query', 'LIMIT', '0', '5']); + 'FT.SEARCH', 'index', 'query', 'LIMIT', '0', '5'], + commandOptions({ returnBuffers: true }) + ); }); it("sends the expected command when given a sort", async () => { @@ -42,7 +46,9 @@ describe("Client", () => { sort: { field: 'sortField', order: 'ASC' } }); expect(redis.sendCommand).toHaveBeenCalledWith([ - 'FT.SEARCH', 'index', 'query', 'SORTBY', 'sortField', 'ASC']); + 'FT.SEARCH', 'index', 'query', 'SORTBY', 'sortField', 'ASC'], + commandOptions({ returnBuffers: true }) + ); }); it("sends the expected command when keysOnly is set to false", async () => { @@ -52,7 +58,9 @@ describe("Client", () => { keysOnly: false }); expect(redis.sendCommand).toHaveBeenCalledWith([ - 'FT.SEARCH', 'index', 'query']); + 'FT.SEARCH', 'index', 'query'], + commandOptions({ returnBuffers: true }) + ); }); it("sends the expected command when keysOnly is set to true", async () => { @@ -62,7 +70,9 @@ describe("Client", () => { keysOnly: true }); expect(redis.sendCommand).toHaveBeenCalledWith([ - 'FT.SEARCH', 'index', 'query', 'RETURN', '0']); + 'FT.SEARCH', 'index', 'query', 'RETURN', '0'], + commandOptions({ returnBuffers: true }) + ); }); it("sends the expected command with all options", async () => { @@ -75,7 +85,9 @@ describe("Client", () => { }); expect(redis.sendCommand).toHaveBeenCalledWith([ 'FT.SEARCH', 'index', 'query', 'LIMIT', '0', '5', - 'SORTBY', 'sortField', 'ASC', 'RETURN', '0']); + 'SORTBY', 'sortField', 'ASC', 'RETURN', '0'], + commandOptions({ returnBuffers: true }) + ); }); }); From 35037a6651116714b87b85c0333581f1befeeac6 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Wed, 6 Jul 2022 09:48:05 -0600 Subject: [PATCH 19/28] Fix node 14 CI (?) Try adding esbuild as direct dependency --- package-lock.json | 548 +++++++++++++++++++++++++++++++++++++++++----- package.json | 1 + 2 files changed, 494 insertions(+), 55 deletions(-) diff --git a/package-lock.json b/package-lock.json index 082d9c72..c36dde95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@types/node": "^18.0.0", "@vitest/ui": "^0.17.1", "c8": "^7.11.3", + "esbuild": "^0.14.48", "tsup": "^6.1.2", "typedoc": "^0.23.2", "typedoc-plugin-markdown": "^3.13.1", @@ -521,9 +522,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", - "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", + "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", "dev": true, "hasInstallScript": true, "bin": { @@ -533,32 +534,64 @@ "node": ">=12" }, "optionalDependencies": { - "esbuild-android-64": "0.14.47", - "esbuild-android-arm64": "0.14.47", - "esbuild-darwin-64": "0.14.47", - "esbuild-darwin-arm64": "0.14.47", - "esbuild-freebsd-64": "0.14.47", - "esbuild-freebsd-arm64": "0.14.47", - "esbuild-linux-32": "0.14.47", - "esbuild-linux-64": "0.14.47", - "esbuild-linux-arm": "0.14.47", - "esbuild-linux-arm64": "0.14.47", - "esbuild-linux-mips64le": "0.14.47", - "esbuild-linux-ppc64le": "0.14.47", - "esbuild-linux-riscv64": "0.14.47", - "esbuild-linux-s390x": "0.14.47", - "esbuild-netbsd-64": "0.14.47", - "esbuild-openbsd-64": "0.14.47", - "esbuild-sunos-64": "0.14.47", - "esbuild-windows-32": "0.14.47", - "esbuild-windows-64": "0.14.47", - "esbuild-windows-arm64": "0.14.47" + "esbuild-android-64": "0.14.48", + "esbuild-android-arm64": "0.14.48", + "esbuild-darwin-64": "0.14.48", + "esbuild-darwin-arm64": "0.14.48", + "esbuild-freebsd-64": "0.14.48", + "esbuild-freebsd-arm64": "0.14.48", + "esbuild-linux-32": "0.14.48", + "esbuild-linux-64": "0.14.48", + "esbuild-linux-arm": "0.14.48", + "esbuild-linux-arm64": "0.14.48", + "esbuild-linux-mips64le": "0.14.48", + "esbuild-linux-ppc64le": "0.14.48", + "esbuild-linux-riscv64": "0.14.48", + "esbuild-linux-s390x": "0.14.48", + "esbuild-netbsd-64": "0.14.48", + "esbuild-openbsd-64": "0.14.48", + "esbuild-sunos-64": "0.14.48", + "esbuild-windows-32": "0.14.48", + "esbuild-windows-64": "0.14.48", + "esbuild-windows-arm64": "0.14.48" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", + "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", + "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, "node_modules/esbuild-darwin-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", - "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", + "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", "cpu": [ "x64" ], @@ -571,6 +604,278 @@ "node": ">=12" } }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", + "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", + "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", + "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", + "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", + "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", + "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", + "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", + "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", + "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", + "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", + "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", + "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", + "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", + "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", + "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", + "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", + "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -2637,37 +2942,170 @@ "dev": true }, "esbuild": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.47.tgz", - "integrity": "sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==", - "dev": true, - "requires": { - "esbuild-android-64": "0.14.47", - "esbuild-android-arm64": "0.14.47", - "esbuild-darwin-64": "0.14.47", - "esbuild-darwin-arm64": "0.14.47", - "esbuild-freebsd-64": "0.14.47", - "esbuild-freebsd-arm64": "0.14.47", - "esbuild-linux-32": "0.14.47", - "esbuild-linux-64": "0.14.47", - "esbuild-linux-arm": "0.14.47", - "esbuild-linux-arm64": "0.14.47", - "esbuild-linux-mips64le": "0.14.47", - "esbuild-linux-ppc64le": "0.14.47", - "esbuild-linux-riscv64": "0.14.47", - "esbuild-linux-s390x": "0.14.47", - "esbuild-netbsd-64": "0.14.47", - "esbuild-openbsd-64": "0.14.47", - "esbuild-sunos-64": "0.14.47", - "esbuild-windows-32": "0.14.47", - "esbuild-windows-64": "0.14.47", - "esbuild-windows-arm64": "0.14.47" - } + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", + "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", + "dev": true, + "requires": { + "esbuild-android-64": "0.14.48", + "esbuild-android-arm64": "0.14.48", + "esbuild-darwin-64": "0.14.48", + "esbuild-darwin-arm64": "0.14.48", + "esbuild-freebsd-64": "0.14.48", + "esbuild-freebsd-arm64": "0.14.48", + "esbuild-linux-32": "0.14.48", + "esbuild-linux-64": "0.14.48", + "esbuild-linux-arm": "0.14.48", + "esbuild-linux-arm64": "0.14.48", + "esbuild-linux-mips64le": "0.14.48", + "esbuild-linux-ppc64le": "0.14.48", + "esbuild-linux-riscv64": "0.14.48", + "esbuild-linux-s390x": "0.14.48", + "esbuild-netbsd-64": "0.14.48", + "esbuild-openbsd-64": "0.14.48", + "esbuild-sunos-64": "0.14.48", + "esbuild-windows-32": "0.14.48", + "esbuild-windows-64": "0.14.48", + "esbuild-windows-arm64": "0.14.48" + } + }, + "esbuild-android-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", + "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", + "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", + "dev": true, + "optional": true }, "esbuild-darwin-64": { - "version": "0.14.47", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.47.tgz", - "integrity": "sha512-R6oaW0y5/u6Eccti/TS6c/2c1xYTb1izwK3gajJwi4vIfNs1s8B1dQzI1UiC9T61YovOQVuePDcfqHLT3mUZJA==", + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", + "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", + "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", + "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", + "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", + "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", + "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", + "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", + "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", + "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", + "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", + "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", + "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", + "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", + "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", + "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", + "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", + "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.14.48", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", + "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", "dev": true, "optional": true }, diff --git a/package.json b/package.json index 41c9f5f1..d6fc7111 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@types/node": "^18.0.0", "@vitest/ui": "^0.17.1", "c8": "^7.11.3", + "esbuild": "^0.14.48", "tsup": "^6.1.2", "typedoc": "^0.23.2", "typedoc-plugin-markdown": "^3.13.1", From ecd586476dba31bf2466b13bbcc4edf5c0438aaf Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 7 Jul 2022 18:50:23 -0600 Subject: [PATCH 20/28] Oxford comma --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ca86c86..382bdbcc 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,7 @@ const studioSchema = new Schema(Studio, { }) ``` -When you create a `Schema`, it modifies the entity you handed it, adding getters and setters for the properties you define. The type those getters and setters accept and return are defined with the type parameter above. Valid values are: `string`, `number`, `boolean`, `string[]`, `date`, `point`, `text` or `binary`. +When you create a `Schema`, it modifies the entity you handed it, adding getters and setters for the properties you define. The type those getters and setters accept and return are defined with the type parameter above. Valid values are: `string`, `number`, `boolean`, `string[]`, `date`, `point`, `text`, or `binary`. The first three do exactly what you think—they define a property that is a [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), a [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), or a [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean). `string[]` does what you'd think as well, specifically defining an [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) of Strings. From 60f6c6eb38e1cf3a8fe2d437cd0f26ba0e9f175d Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 7 Jul 2022 18:54:14 -0600 Subject: [PATCH 21/28] Update to node-redis 4.2.0 Remove encding fix --- lib/client.ts | 4 +--- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/client.ts b/lib/client.ts index a84ec1b7..f3d89efa 100644 --- a/lib/client.ts +++ b/lib/client.ts @@ -216,9 +216,7 @@ export class Client { await isolatedClient .multi() .unlink(key) - // when redis/node-redis#2139 is released, this can be reverted - // .hSet(key, data) - .hSet(key, Object.entries(data)) + .hSet(key, data) .exec(); }); } catch (error: any) { diff --git a/package-lock.json b/package-lock.json index c36dde95..ba33d788 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.3.6", "license": "MIT", "dependencies": { - "redis": "^4.0.4", + "redis": "^4.2.0", "ulid": "^2.3.0" }, "devDependencies": { @@ -117,9 +117,9 @@ } }, "node_modules/@redis/client": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.1.0.tgz", - "integrity": "sha512-xO9JDIgzsZYDl3EvFhl6LC52DP3q3GCMUer8zHgKV6qSYsq1zB+pZs9+T80VgcRogrlRYhi4ZlfX6A+bHiBAgA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.2.0.tgz", + "integrity": "sha512-a8Nlw5fv2EIAFJxTDSSDVUT7yfBGpZO96ybZXzQpgkyLg/dxtQ1uiwTc0EGfzg1mrPjZokeBSEGTbGXekqTNOg==", "dependencies": { "cluster-key-slot": "1.1.0", "generic-pool": "3.8.2", @@ -1759,12 +1759,12 @@ } }, "node_modules/redis": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.1.0.tgz", - "integrity": "sha512-5hvJ8wbzpCCiuN1ges6tx2SAh2XXCY0ayresBmu40/SGusWHFW86TAlIPpbimMX2DFHOX7RN34G2XlPA1Z43zg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.2.0.tgz", + "integrity": "sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==", "dependencies": { "@redis/bloom": "1.0.2", - "@redis/client": "1.1.0", + "@redis/client": "1.2.0", "@redis/graph": "1.0.1", "@redis/json": "1.0.3", "@redis/search": "1.0.6", @@ -2630,9 +2630,9 @@ "requires": {} }, "@redis/client": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.1.0.tgz", - "integrity": "sha512-xO9JDIgzsZYDl3EvFhl6LC52DP3q3GCMUer8zHgKV6qSYsq1zB+pZs9+T80VgcRogrlRYhi4ZlfX6A+bHiBAgA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.2.0.tgz", + "integrity": "sha512-a8Nlw5fv2EIAFJxTDSSDVUT7yfBGpZO96ybZXzQpgkyLg/dxtQ1uiwTc0EGfzg1mrPjZokeBSEGTbGXekqTNOg==", "requires": { "cluster-key-slot": "1.1.0", "generic-pool": "3.8.2", @@ -3723,12 +3723,12 @@ } }, "redis": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.1.0.tgz", - "integrity": "sha512-5hvJ8wbzpCCiuN1ges6tx2SAh2XXCY0ayresBmu40/SGusWHFW86TAlIPpbimMX2DFHOX7RN34G2XlPA1Z43zg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.2.0.tgz", + "integrity": "sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==", "requires": { "@redis/bloom": "1.0.2", - "@redis/client": "1.1.0", + "@redis/client": "1.2.0", "@redis/graph": "1.0.1", "@redis/json": "1.0.3", "@redis/search": "1.0.6", diff --git a/package.json b/package.json index d6fc7111..f6a1c529 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "vitest": "^0.20.0" }, "dependencies": { - "redis": "^4.0.4", + "redis": "^4.2.0", "ulid": "^2.3.0" } } From 115655811621264189f7df7cf495cf7a5319ceff Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 7 Jul 2022 19:27:11 -0600 Subject: [PATCH 22/28] Store binary as numeric array for Json data structure Enable vector indexing --- README.md | 2 +- lib/entity/fields/entity-binary-field.ts | 7 +- lib/schema/builders/json-schema-builder.ts | 5 +- spec/functional/vector.spec.ts | 2 +- spec/helpers/example-data.ts | 4 +- spec/unit/entity/entity-binary-field.spec.ts | 18 +-- spec/unit/schema/binary-hash-fields.spec.ts | 2 +- spec/unit/schema/binary-json-fields.spec.ts | 133 ++++++++++++++++--- 8 files changed, 137 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 382bdbcc..370219f3 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,7 @@ const point = { longitude: 12.34, latitude: 56.78 } A `text` field is a lot like a `string`. If you're just reading and writing objects, they are identical. But if you want to *search* on them, they are very, very different. I'll cover that in detail when I talk about [using RediSearch](#-using-redisearch) but the tl;dr is that `string` fields can only be matched on their whole value—no partial matches—and are best for keys while `text` fields have full-text search enabled on them and are optimized for human-readable text. -A `binary` field is a binary blob of data using a `Buffer` object. For Hash data structures it will be stored as a binary field in Redis, for JSON data structures it will be serialized to a Base64 string. The `binary` field stored in a Hash data structure can be indexed as a [Vector Similarity](https://redis.io/docs/stack/search/reference/vectors/) field. When stored in a JSON data structure it will be automatically unindexed. +A `binary` field is a binary blob of data using a `Buffer` object. For Hash data structures it will be stored as a binary field in Redis, for JSON data structures it will be serialized to a numeric array. The `binary` field can be indexed as a [Vector Similarity](https://redis.io/docs/stack/search/reference/vectors/) field. Additional field options can be set depending on the field type. These correspond to the [Field Options](https://redis.io/commands/ft.create/#field-options) avialable when creating a RediSearch full-text index. Other than the `separator` option, these only affect how content is indexed and searched. diff --git a/lib/entity/fields/entity-binary-field.ts b/lib/entity/fields/entity-binary-field.ts index 17a8fe42..b9802437 100644 --- a/lib/entity/fields/entity-binary-field.ts +++ b/lib/entity/fields/entity-binary-field.ts @@ -5,12 +5,15 @@ import { EntityValue } from "../entity-value"; export class EntityBinaryField extends EntityField { toRedisJson(): RedisJsonData { const data: RedisJsonData = {}; - if (this.value !== null) data[this.name] = this.valueAsBuffer.toString('base64') + if (this.value !== null) data[this.name] = [...this.valueAsBuffer] return data; } fromRedisJson(value: any) { - if (value !== null) this.value = Buffer.from(value, 'base64'); + if (!this.isBuffer(value)) { + throw Error(`Non-binary value of '${value}' read from Redis for binary field.`) + } + this.value = Buffer.from([...value]); } toRedisHash(): RedisHashData { diff --git a/lib/schema/builders/json-schema-builder.ts b/lib/schema/builders/json-schema-builder.ts index 93290fc9..ef34183a 100644 --- a/lib/schema/builders/json-schema-builder.ts +++ b/lib/schema/builders/json-schema-builder.ts @@ -57,10 +57,9 @@ export class JsonSchemaBuilder extends SchemaBuilder { const results = await redis.sendCommand([ 'FT.SEARCH', 'Product:index', '*=>[KNN 2 @image $query_vector]', 'PARAMS', '2', 'query_vector', Buffer.from(products[0].image, 'hex'), - 'RETURN', '3', '__image_score name price', + 'RETURN', '3', '__image_score", "name", "price', 'SORTBY', '__image_score', 'DIALECT', '2' ]) as any[] diff --git a/spec/helpers/example-data.ts b/spec/helpers/example-data.ts index 23552149..1e1a30d7 100644 --- a/spec/helpers/example-data.ts +++ b/spec/helpers/example-data.ts @@ -59,8 +59,8 @@ export const SOME_MORE_STRINGS: Array = ['charlie', 'delta', 'echo']; export const SOME_MORE_STRINGS_JSON: string = JSON.stringify(SOME_MORE_STRINGS); export const SOME_MORE_STRINGS_JOINED: string = SOME_MORE_STRINGS.join('|'); -export const A_BUFFER = Buffer.from([1, 2, 3, 4, 5, 6]) -export const A_BUFFER_BASE64 = 'AQIDBAUG' +export const A_BUFFER_VALUES = [1, 2, 3, 4, 5, 6] +export const A_BUFFER = Buffer.from(A_BUFFER_VALUES) export type SampleEntityData = { aString: string | null; diff --git a/spec/unit/entity/entity-binary-field.spec.ts b/spec/unit/entity/entity-binary-field.spec.ts index abdd6f86..23132896 100644 --- a/spec/unit/entity/entity-binary-field.spec.ts +++ b/spec/unit/entity/entity-binary-field.spec.ts @@ -1,12 +1,12 @@ import { FieldDefinition } from "../../../lib"; import { EntityBinaryField } from "$lib/entity/fields"; -import { A_DATE, A_NUMBER, A_NUMBER_STRING, A_POINT, A_STRING, SOME_STRINGS, A_BUFFER, A_BUFFER_BASE64 } from "../../helpers/example-data"; +import { A_DATE, A_NUMBER, A_NUMBER_STRING, A_POINT, A_STRING, SOME_STRINGS, A_BUFFER_VALUES, A_BUFFER } from "../../helpers/example-data"; const FIELD_NAME = 'foo'; const FIELD_DEF: FieldDefinition = { type: 'binary' }; const EXPECTED_NULL_JSON_DATA = {}; const EXPECTED_NULL_HASH_DATA = {}; -const EXPECTED_JSON_DATA = { foo: A_BUFFER_BASE64 }; +const EXPECTED_JSON_DATA = { foo: A_BUFFER_VALUES }; const EXPECTED_HASH_DATA = { foo: A_BUFFER }; describe("EntityBinaryField", () => { @@ -25,18 +25,14 @@ describe("EntityBinaryField", () => { it("converts to the expected Redis Hash data", () => expect(field.toRedisHash()).toEqual(EXPECTED_NULL_HASH_DATA)); describe("when loaded from Redis JSON data", () => { - beforeEach(() => field.fromRedisJson(A_BUFFER_BASE64)); + beforeEach(() => field.fromRedisJson(A_BUFFER)); it("has the expected value", () => expect(field.value).toEqual(A_BUFFER)); }); - describe("when loaded from Redis JSON data containing a null", () => { - beforeEach(() => field.fromRedisJson(null)); - it("has the expected value", () => expect(field.value).toBeNull()); - }); - - it("when loaded from Redis JSON data containing invalid base64", () => { - beforeEach(() => field.fromRedisJson('^~$')); - it("has has the null value", () => expect(field.value).toBeNull()); + it("complains when loaded from invalid Redis Json data", () => { + // @ts-ignore: JavaScript trap + expect(() => field.fromRedisJson('foo')) + .toThrow("Non-binary value of 'foo' read from Redis for binary field."); }); describe("when loaded from Redis Hash data", () => { diff --git a/spec/unit/schema/binary-hash-fields.spec.ts b/spec/unit/schema/binary-hash-fields.spec.ts index db848ec0..aa2734a3 100644 --- a/spec/unit/schema/binary-hash-fields.spec.ts +++ b/spec/unit/schema/binary-hash-fields.spec.ts @@ -55,7 +55,7 @@ describe("Schema", () => { }], // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing - // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence + // but keep the schema definition, so we'll assume that NOINDEX should take precendence ["that defines an unindexed FLAT vector for a HASH", { schemaDef: { aField: { type: 'binary', indexed: false, vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, dataStructure: 'HASH', diff --git a/spec/unit/schema/binary-json-fields.spec.ts b/spec/unit/schema/binary-json-fields.spec.ts index d39ae483..a998bea0 100644 --- a/spec/unit/schema/binary-json-fields.spec.ts +++ b/spec/unit/schema/binary-json-fields.spec.ts @@ -3,34 +3,137 @@ import { Entity } from '$lib/entity/entity'; import { SchemaDefinition } from '$lib/schema/definition'; import { DataStructure } from '$lib/schema/options'; -const warnSpy = vi.spyOn(global.console, 'warn').mockImplementation(() => {}) - describe("Schema", () => { describe.each([ - ["that defines a binary for a JSON", { + ["that defines an unindexed binary", { schemaDef: { aField: { type: 'binary' } } as SchemaDefinition, dataStructure: 'JSON', expectedRedisSchema: [ '$.aField', 'AS', 'aField', 'NOINDEX' - ], - expectedWarning: null + ] + }], + + ["that defines a FLAT / 512 / COSINE vector for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + ["that defines a FLAT / 256 / IP vector for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'FLAT', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' + ] + }], + + ["that defines a FLAT / 1024 / L2 vector for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'FLAT', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' + ] + }], + + ["that defines a FLAT / 512 / COSINE vector with block_size for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', block_size: 512*512 } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'FLAT', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'BLOCK_SIZE', '262144' + ] + }], + + ["that defines an aliased FLAT / 512 / COSINE vector for a JSON", { + schemaDef: { aField: { type: 'binary', alias: 'anotherField', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.anotherField', 'AS', 'anotherField', 'VECTOR', 'FLAT', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing + // but keep the schema definition, so we'll assume that NOINDEX should take precendence + ["that defines an unindexed FLAT vector for a JSON", { + schemaDef: { aField: { type: 'binary', indexed: false, vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'NOINDEX' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + ["that defines a HNSW / 256 / IP vector for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 256, distance_metric: 'IP' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '256', 'DISTANCE_METRIC', 'IP' + ] + }], + + ["that defines a HNSW / 1024 / L2 vector for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 1024, distance_metric: 'L2' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '1024', 'DISTANCE_METRIC', 'L2' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with M for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', m: 8 } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'M', '8' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with EF_CONSTRUCTION for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_construction: 250 } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS', 'aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_CONSTRUCTION', '250' + ] + }], + + ["that defines a HNSW / 512 / COSINE vector with EF_RUNTIME for a JSON", { + schemaDef: { aField: { type: 'binary', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE', ef_runtime: 20 } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS','aField', 'VECTOR', 'HNSW', '8', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE', 'EF_RUNTIME', '20' + ] + }], + + ["that defines an aliased HNSW / 512 / COSINE vector for a JSON", { + schemaDef: { aField: { type: 'binary', alias: 'anotherField', vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.anotherField', 'AS', 'anotherField', 'VECTOR', 'HNSW', '6', 'TYPE', 'FLOAT32', 'DIM', '512', 'DISTANCE_METRIC', 'COSINE' + ] + }], + + // NOTE: it makes little sense to do this, but maybe someone wants to turn off indexing + // but keep the schema definition, so we'll assume that NOINDEX shoudl take precendence + ["that defines an unindexed HNSW vector for a JSON", { + schemaDef: { aField: { type: 'binary', indexed: false, vector: { algorithm: 'HNSW', dim: 512, distance_metric: 'COSINE' } } } as SchemaDefinition, + dataStructure: 'JSON', + expectedRedisSchema: [ + '$.aField', 'AS','aField', 'NOINDEX' + ] }], ])("%s", (_, data) => { class TestEntity extends Entity {} - if (data.expectedWarning) { - it("generates the expected warning", () => { - expect(warnSpy).toHaveBeenCalledWith(data.expectedWarning); - }); - } else { - it("does not generate a warning", () => { - expect(warnSpy).not.toHaveBeenCalled(); - }); - } - it("generates a Redis schema for the field", () => { let schemaDef = data.schemaDef; let dataStructure = data.dataStructure as DataStructure; From 6505e0527c6ad99380052d660b87316210028776 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 7 Jul 2022 19:41:02 -0600 Subject: [PATCH 23/28] Remove direct esbuild dependency Regen package-lock.json --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index f6a1c529..22d0d08c 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "@types/node": "^18.0.0", "@vitest/ui": "^0.17.1", "c8": "^7.11.3", - "esbuild": "^0.14.48", "tsup": "^6.1.2", "typedoc": "^0.23.2", "typedoc-plugin-markdown": "^3.13.1", From 57ec10d6efe75a6ac6a5d47c485e31fcfa680015 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Thu, 7 Jul 2022 19:45:17 -0600 Subject: [PATCH 24/28] Re-add esbuild dependency --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 22d0d08c..f6a1c529 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@types/node": "^18.0.0", "@vitest/ui": "^0.17.1", "c8": "^7.11.3", + "esbuild": "^0.14.48", "tsup": "^6.1.2", "typedoc": "^0.23.2", "typedoc-plugin-markdown": "^3.13.1", From 14f3dcdfce5f6d4e929cd5af119b6ef0e01fd6d5 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Tue, 13 Dec 2022 11:48:15 -0700 Subject: [PATCH 25/28] update dependencies try without esbuild --- package-lock.json | 4383 +++++++++++++++++++++++++++++---------------- package.json | 7 +- vitest.config.js | 39 +- 3 files changed, 2879 insertions(+), 1550 deletions(-) diff --git a/package-lock.json b/package-lock.json index ba33d788..985b9fbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,14 +14,13 @@ }, "devDependencies": { "@types/node": "^18.0.0", - "@vitest/ui": "^0.17.1", + "@vitest/ui": "^0.25.0", "c8": "^7.11.3", - "esbuild": "^0.14.48", "tsup": "^6.1.2", "typedoc": "^0.23.2", "typedoc-plugin-markdown": "^3.13.1", "typescript": "^4.7.2", - "vitest": "^0.20.0" + "vitest": "^0.25.0" }, "engines": { "node": ">= 14" @@ -33,972 +32,1051 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "cpu": [ + "arm" + ], "dev": true, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "node_modules/@esbuild/android-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.5.tgz", + "integrity": "sha512-BCWkmAqFoW6xXzz6Up16bU0vdZqe23UxkrabbrmXXUuH27Tts3LVcHFCi/dGLYa6ZqC/txhtJm2kAJdoyOfHxg==", + "cpu": [ + "arm64" + ], "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=6.0.0" + "node": ">=12" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "node_modules/@esbuild/android-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.5.tgz", + "integrity": "sha512-E0R7d0dy9+QlpMps8gJXXhtfn+fQFaTXbq8kV2u/HfHyyhxr4nIIuXZCcYxxA9LSKnsFBBbSQIGDUVY9FGgx0w==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.5.tgz", + "integrity": "sha512-4HlbUMy50cRaHGVriBjShs46WRPshtnVOqkxEGhEuDuJhgZ3regpWzaQxXOcDXFvVwue8RiqDAAcOi/QlVLE6Q==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">= 8" + "node": ">=12" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.5.tgz", + "integrity": "sha512-ZDCAxAPwbtKJ5YxRZusQKDFuywH+7YNKbilss0DCRPtXMxrKRZETcuSfcgIWGYBBc+ypdOazousx3yZss2Az0A==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">= 8" + "node": ">=12" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.5.tgz", + "integrity": "sha512-w0dJ8om4KiagLCHURgwxXVWzi5xa0W7F5woMxzWO+LDCebrlyZUhCIbSXUKa4qD3XbdG7K4Y8N4mLDRMkZzMuw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">= 8" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.21", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", - "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", - "dev": true - }, - "node_modules/@redis/bloom": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz", - "integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==", - "peerDependencies": { - "@redis/client": "^1.0.0" + "node": ">=12" } }, - "node_modules/@redis/client": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.2.0.tgz", - "integrity": "sha512-a8Nlw5fv2EIAFJxTDSSDVUT7yfBGpZO96ybZXzQpgkyLg/dxtQ1uiwTc0EGfzg1mrPjZokeBSEGTbGXekqTNOg==", - "dependencies": { - "cluster-key-slot": "1.1.0", - "generic-pool": "3.8.2", - "yallist": "4.0.0" - }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.5.tgz", + "integrity": "sha512-qCdC0T7XUxngX8otO4nmPUE/cHZfvF8jk+GMr9qkAGP0nIMACD7t/AWoY2N5rsn5/dOJ1VKM/aMF4wCFBP5AqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">=14" - } - }, - "node_modules/@redis/graph": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz", - "integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/json": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz", - "integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/search": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.0.6.tgz", - "integrity": "sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/time-series": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz", - "integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==", - "peerDependencies": { - "@redis/client": "^1.0.0" + "node": ">=12" } }, - "node_modules/@types/chai": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", - "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", - "dev": true - }, - "node_modules/@types/chai-subset": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", - "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", + "node_modules/@esbuild/linux-arm": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.5.tgz", + "integrity": "sha512-6crdpqwFjl+DObBgwaJMtB+VWrZd87Jy05gQTERysc1ujnUJNCJzemUcRDT5hM34dzTYThlXfFW32qQy9QpPGQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "@types/chai": "*" + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" } }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", - "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==", - "dev": true - }, - "node_modules/@vitest/ui": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.17.1.tgz", - "integrity": "sha512-B4PGDk5IZ10HT9GzR0NQ96VEphWY9dTf1yqBGNjPk2c7wQnhZJdHzv3tgFQiyFK5YR1cjtOV918QHCnptV4r5w==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.5.tgz", + "integrity": "sha512-h84QZmBhBdEclyxf9Wm/UESY6ITI7/gYLNvj/3emhDd0ILAqwHdWnMDmKqqubrMcpb1O4sWOYRm7EZ+Av8eGiQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "sirv": "^2.0.2" + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" } }, - "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==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.5.tgz", + "integrity": "sha512-P1WNzGqy6ipvbt8iNoYY66+qUANCiM80D8bGJIU8jqSZ613eG0lUWBePi4xQazcNgIi9tSiCa9Ba3f4krXtQDw==", + "cpu": [ + "ia32" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=8" + "node": ">=12" } }, - "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==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.5.tgz", + "integrity": "sha512-r8wKqs+rl4gIT/xDB6CHMaYcvvyZ7tWf5LulH9NsDvgQEy3gIXQPR4Oy9tYrjM75uKkvBv1uw15Iz4EWsvve9Q==", + "cpu": [ + "loong64" + ], "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=12" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.5.tgz", + "integrity": "sha512-0WMhOlwfeeAp6KMx3E6LZKDN6INk4Me8dwIw1XMSFvmE6r31vRnwXkrQlAk5FI44KZ/rIi+yynRZqEd7UJAV2g==", + "cpu": [ + "mips64el" + ], "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">= 8" + "node": ">=12" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.5.tgz", + "integrity": "sha512-29x+DtRGcYH0Sh3QSnoF+D2SYkHLxwx5AugoGLIlVtcVqDb4fEb654d67k9VcAR2RiTAYUZ764KXzWB+ItQfgw==", + "cpu": [ + "ppc64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.5.tgz", + "integrity": "sha512-ZX4SSKOJUcuqFNDydfN4yCo9je9f1T72Pj+RLsAGRiuiREVCwRkXIBp810C01+MdPqYExp322kY78ISEq5XGLQ==", + "cpu": [ + "riscv64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": "*" + "node": ">=12" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.5.tgz", + "integrity": "sha512-pYY86RiLD1s5RN8q0aMhWD44NiHmAZxv2bSzaNlL63/ibWETld+m6F+MPh9+ZNOqGJw53E/0qHukYI5Lm+1k7A==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/bundle-require": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-3.0.4.tgz", - "integrity": "sha512-VXG6epB1yrLAvWVQpl92qF347/UXmncQj7J3U8kZEbdVZ1ZkQyr4hYeL/9RvcE8vVVdp53dY78Fd/3pqfRqI1A==", + "node_modules/@esbuild/linux-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.5.tgz", + "integrity": "sha512-vsOwzKN+4NenUTyuoWLmg5dAuO8JKuLD9MXSeENA385XucuOZbblmOMwwgPlHsgVRtSjz38riqPJU2ALI/CWYQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "load-tsconfig": "^0.2.0" - }, + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "esbuild": ">=0.13" + "node": ">=12" } }, - "node_modules/c8": { - "version": "7.11.3", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.3.tgz", - "integrity": "sha512-6YBmsaNmqRm9OS3ZbIiL2EZgi1+Xc4O24jL3vMYGE6idixYuGdy76rIfIdltSKDj9DpLNrcXSonUTR1miBD0wA==", + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.5.tgz", + "integrity": "sha512-ZhfELxpZLXg7OidX9MrjgQNhjhYx3GXm59EAQVZds8GTyOOPj+Hg7ttKenlXoV8PZVkoCm0dgoWXzhasZJGfWw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@istanbuljs/schema": "^0.1.3", - "find-up": "^5.0.0", - "foreground-child": "^2.0.0", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-reports": "^3.1.4", - "rimraf": "^3.0.2", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.0.0", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9" - }, - "bin": { - "c8": "bin/c8.js" - }, + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, "engines": { - "node": ">=10.12.0" + "node": ">=12" } }, - "node_modules/cac": { - "version": "6.7.12", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.12.tgz", - "integrity": "sha512-rM7E2ygtMkJqD9c7WnFU6fruFcN3xe4FM5yUmgxhZzIKJk4uHl9U/fhwdajGFQbQuv43FAUo1Fe8gX/oIKDeSA==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.5.tgz", + "integrity": "sha512-2HY2L0afN8IUgvxCAWY04bB6mhHSnC7YNGM2hmEkyAgP+n8jpZgGjiRokuk3AQ0g0IpX8h0KnS+xaznGEr5CGw==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.5.tgz", + "integrity": "sha512-Q7+HbDnW52LLW8YIU5h0sYZ23TvaaC0vuwiIbJUa91Qr77NKNJCe8stfunN1TRZo+6OwGpM3MrdUcUVUfr5wuA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", - "pathval": "^1.1.1", - "type-detect": "^4.0.5" - }, + "optional": true, + "os": [ + "sunos" + ], + "peer": true, "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.5.tgz", + "integrity": "sha512-KcegNS7IgLm/cAcjIW3kZyLiZi/p8I+A2a6OonDA77em9xHewdA2yTA+9pO4gr77MkXATcnDAFBrWw5oLHIZkQ==", + "cpu": [ + "arm64" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": "*" + "node": ">=12" } }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.5.tgz", + "integrity": "sha512-ReUCJSzLNGH6WcvwjMzpEy2SX5GTZBeRTvCdklN4DT2YrgRIe82lYVikVHwA7fdiL3xHKvmdiicMqxE8QYmxrA==", + "cpu": [ + "ia32" + ], "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } + "optional": true, + "os": [ + "win32" ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, + "peer": true, "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=12" } }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "node_modules/@esbuild/win32-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.5.tgz", + "integrity": "sha512-q00Jasz6/wCOD2XxRj4GEwj27u1zfpiBniL1ip3/YGGcYtvOoGKCNSS47sufO/8ixEgrSYDlkglSd6CxcS7m0g==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "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==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=8" } }, - "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==", - "dev": true - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true, "engines": { - "node": ">= 6" + "node": ">=6.0.0" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { - "safe-buffer": "~5.1.1" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" }, "engines": { "node": ">= 8" } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">= 8" } }, - "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { - "type-detect": "^4.0.0" + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" }, "engines": { - "node": ">=0.12" + "node": ">= 8" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "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/@polka/url": { + "version": "1.0.0-next.21", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz", + "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, - "node_modules/esbuild": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", - "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" + "node_modules/@redis/bloom": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.1.0.tgz", + "integrity": "sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.4.2.tgz", + "integrity": "sha512-oUdEjE0I7JS5AyaAjkD3aOXn9NhO7XKyPyXEyrgFDu++VrVBHUPnV6dgEya9TcMuj5nIJRuCzCm8ZP+c9zCHPw==", + "dependencies": { + "cluster-key-slot": "1.1.1", + "generic-pool": "3.9.0", + "yallist": "4.0.0" }, - "optionalDependencies": { - "esbuild-android-64": "0.14.48", - "esbuild-android-arm64": "0.14.48", - "esbuild-darwin-64": "0.14.48", - "esbuild-darwin-arm64": "0.14.48", - "esbuild-freebsd-64": "0.14.48", - "esbuild-freebsd-arm64": "0.14.48", - "esbuild-linux-32": "0.14.48", - "esbuild-linux-64": "0.14.48", - "esbuild-linux-arm": "0.14.48", - "esbuild-linux-arm64": "0.14.48", - "esbuild-linux-mips64le": "0.14.48", - "esbuild-linux-ppc64le": "0.14.48", - "esbuild-linux-riscv64": "0.14.48", - "esbuild-linux-s390x": "0.14.48", - "esbuild-netbsd-64": "0.14.48", - "esbuild-openbsd-64": "0.14.48", - "esbuild-sunos-64": "0.14.48", - "esbuild-windows-32": "0.14.48", - "esbuild-windows-64": "0.14.48", - "esbuild-windows-arm64": "0.14.48" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", - "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=12" + "node": ">=14" } }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", - "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" + "node_modules/@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", - "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" + "node_modules/@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", - "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" + "node_modules/@redis/search": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz", + "integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==", + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", - "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" + "node_modules/@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "peerDependencies": { + "@redis/client": "^1.0.0" } }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", - "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", - "cpu": [ - "arm64" - ], + "node_modules/@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "node_modules/@types/chai-subset": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", + "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" + "dependencies": { + "@types/chai": "*" } }, - "node_modules/esbuild-linux-32": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", - "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", - "cpu": [ - "ia32" - ], + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.11.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.14.tgz", + "integrity": "sha512-0KXV57tENYmmJMl+FekeW9V3O/rlcqGQQJ/hNh9r8pKIj304pskWuEd8fCyNT86g/TpO0gcOTiLzsHLEURFMIQ==", + "dev": true + }, + "node_modules/@vitest/ui": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.25.8.tgz", + "integrity": "sha512-wfuhghldD5QHLYpS46GK8Ru8P3XcMrWvFjRQD21KNzc9Y/qtJsqoC8KmT6xWVkMNw4oHYixpo3a4ZySRJdserw==", "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "dependencies": { + "sirv": "^2.0.2" } }, - "node_modules/esbuild-linux-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", - "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", - "cpu": [ - "x64" - ], + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=12" + "node": ">=0.4.0" } }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", - "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", - "cpu": [ - "arm" - ], + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": ">=0.4.0" } }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", - "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", - "cpu": [ - "arm64" - ], + "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==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", - "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", - "cpu": [ - "mips64el" - ], + "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==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", - "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", - "cpu": [ - "ppc64" - ], + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, "engines": { - "node": ">=12" + "node": ">= 8" } }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", - "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", - "cpu": [ - "riscv64" - ], + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", - "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", - "cpu": [ - "s390x" - ], + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=12" + "node": "*" } }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", - "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", - "cpu": [ - "x64" - ], + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, - "optional": true, - "os": [ - "netbsd" - ], "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", - "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", - "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", - "cpu": [ - "x64" - ], + "node_modules/bundle-require": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-3.1.2.tgz", + "integrity": "sha512-Of6l6JBAxiyQ5axFxUM6dYeP/W7X2Sozeo/4EYB9sJhL+dqL7TKjg+shwxp6jlu/6ZSERfsYtIpSJ1/x3XkAEA==", "dev": true, - "optional": true, - "os": [ - "sunos" - ], + "dependencies": { + "load-tsconfig": "^0.2.0" + }, "engines": { - "node": ">=12" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.13" } }, - "node_modules/esbuild-windows-32": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", - "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", - "cpu": [ - "ia32" - ], + "node_modules/c8": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", + "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^2.0.0", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-reports": "^3.1.4", + "rimraf": "^3.0.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.0.0", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9" + }, + "bin": { + "c8": "bin/c8.js" + }, "engines": { - "node": ">=12" + "node": ">=10.12.0" } }, - "node_modules/esbuild-windows-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", - "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", - "cpu": [ - "x64" - ], + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", - "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", - "cpu": [ - "arm64" - ], + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, "engines": { - "node": ">=12" + "node": ">=4" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", "dev": true, "engines": { - "node": ">=6" + "node": "*" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=10" + "node": ">= 8.10.0" }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/execa/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, - "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "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==", "dev": true, "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8.6.0" + "node": ">=7.0.0" } }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "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==", + "dev": true + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true, - "dependencies": { - "reusify": "^1.0.4" + "engines": { + "node": ">= 6" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "to-regex-range": "^5.0.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">= 8" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "ms": "2.1.2" }, "engines": { - "node": ">=10" + "node": ">=6.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" + "type-detect": "^4.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "hasInstallScript": true, - "optional": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "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==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.5.tgz", + "integrity": "sha512-te0zG5CDzAxhnBKeddXUtK8xDnYL6jv100ekldhtUk0ALXPXcDAtuH0fAR7rbKwUdz3bOey6HVq2N+aWCKZ1cw==", + "dev": true, + "hasInstallScript": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.5", + "@esbuild/android-arm64": "0.16.5", + "@esbuild/android-x64": "0.16.5", + "@esbuild/darwin-arm64": "0.16.5", + "@esbuild/darwin-x64": "0.16.5", + "@esbuild/freebsd-arm64": "0.16.5", + "@esbuild/freebsd-x64": "0.16.5", + "@esbuild/linux-arm": "0.16.5", + "@esbuild/linux-arm64": "0.16.5", + "@esbuild/linux-ia32": "0.16.5", + "@esbuild/linux-loong64": "0.16.5", + "@esbuild/linux-mips64el": "0.16.5", + "@esbuild/linux-ppc64": "0.16.5", + "@esbuild/linux-riscv64": "0.16.5", + "@esbuild/linux-s390x": "0.16.5", + "@esbuild/linux-x64": "0.16.5", + "@esbuild/netbsd-x64": "0.16.5", + "@esbuild/openbsd-x64": "0.16.5", + "@esbuild/sunos-x64": "0.16.5", + "@esbuild/win32-arm64": "0.16.5", + "@esbuild/win32-ia32": "0.16.5", + "@esbuild/win32-x64": "0.16.5" + } + }, + "node_modules/esbuild/node_modules/@esbuild/android-arm": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.5.tgz", + "integrity": "sha512-eNkNuLSKpbZTH0BZklJ9B9Sml7fTIamhrQNBwftsEHCUuSLBVunzV3LfghryVGpE5lSkOwOfeX6gR6+3yLaEfQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, "os": [ "darwin" ], @@ -1013,9 +1091,9 @@ "dev": true }, "node_modules/generic-pool": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", - "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", "engines": { "node": ">= 4" } @@ -1038,6 +1116,18 @@ "node": "*" } }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -1111,6 +1201,15 @@ "uglify-js": "^3.1.4" } }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1148,9 +1247,9 @@ } }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true, "engines": { "node": ">= 4" @@ -1185,9 +1284,9 @@ } }, "node_modules/is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -1299,15 +1398,15 @@ } }, "node_modules/jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, "node_modules/lilconfig": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", - "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", "dev": true, "engines": { "node": ">=10" @@ -1362,9 +1461,9 @@ "dev": true }, "node_modules/loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", "dev": true, "dependencies": { "get-func-name": "^2.0.0" @@ -1392,9 +1491,9 @@ } }, "node_modules/marked": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz", - "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.4.tgz", + "integrity": "sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==", "dev": true, "bin": { "marked": "bin/marked.js" @@ -1453,10 +1552,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mrmime": { "version": "1.0.1", @@ -1665,9 +1767,9 @@ } }, "node_modules/postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", "dev": true, "funding": [ { @@ -1759,16 +1861,16 @@ } }, "node_modules/redis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.2.0.tgz", - "integrity": "sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.5.1.tgz", + "integrity": "sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==", "dependencies": { - "@redis/bloom": "1.0.2", - "@redis/client": "1.2.0", - "@redis/graph": "1.0.1", - "@redis/json": "1.0.3", - "@redis/search": "1.0.6", - "@redis/time-series": "1.0.3" + "@redis/bloom": "1.1.0", + "@redis/client": "1.4.2", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.0", + "@redis/time-series": "1.0.4" } }, "node_modules/require-directory": { @@ -1831,556 +1933,1338 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rollup": { - "version": "2.75.7", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.7.tgz", - "integrity": "sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==", + "node_modules/rollup": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.4.tgz", + "integrity": "sha512-jN9rx3k5pfg9H9al0r0y1EYKSeiRANZRYX32SuNXAnKzh6cVyf4LZVto1KAuDnbHT03E1CpsgqDKaqQ8FZtgxw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "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": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shiki": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz", + "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-oniguruma": "^1.6.1", + "vscode-textmate": "^6.0.0" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz", + "integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "dependencies": { + "whatwg-url": "^7.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-literal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.0.tgz", + "integrity": "sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==", + "dev": true, + "dependencies": { + "acorn": "^8.8.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/sucrase": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.29.0.tgz", + "integrity": "sha512-bZPAuGA5SdFHuzqIhTAqt9fvNEo9rESqXIG3oiKdF8K4UmkQxC4KlNL3lVyAErXp+mPvUqZ5l13qx6TrDIGf3A==", + "dev": true, + "dependencies": { + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinybench": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.3.1.tgz", + "integrity": "sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.0.tgz", + "integrity": "sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.0.2.tgz", + "integrity": "sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz", + "integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/tsup": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-6.5.0.tgz", + "integrity": "sha512-36u82r7rYqRHFkD15R20Cd4ercPkbYmuvRkz3Q1LCm5BsiFNUgpo36zbjVhCOgvjyxNBWNKHsaD5Rl8SykfzNA==", + "dev": true, + "dependencies": { + "bundle-require": "^3.1.2", + "cac": "^6.7.12", + "chokidar": "^3.5.1", + "debug": "^4.3.1", + "esbuild": "^0.15.1", + "execa": "^5.0.0", + "globby": "^11.0.3", + "joycon": "^3.0.1", + "postcss-load-config": "^3.0.1", + "resolve-from": "^5.0.0", + "rollup": "^3.2.5", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.20.3", + "tree-kill": "^1.2.2" + }, + "bin": { + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": "^4.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" + } + }, + "node_modules/tsup/node_modules/esbuild-android-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-android-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-darwin-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-darwin-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-freebsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-freebsd-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-linux-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-linux-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-linux-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-linux-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-linux-mips64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-linux-ppc64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsup/node_modules/esbuild-linux-riscv64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", + "cpu": [ + "riscv64" + ], "dev": true, - "bin": { - "rollup": "dist/bin/rollup" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=10.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "node": ">=12" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/tsup/node_modules/esbuild-linux-s390x": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", + "cpu": [ + "s390x" + ], "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } + "optional": true, + "os": [ + "linux" ], - "dependencies": { - "queue-microtask": "^1.2.2" + "engines": { + "node": ">=12" } }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "node_modules/tsup/node_modules/esbuild-netbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", + "cpu": [ + "x64" + ], "dev": true, - "bin": { - "semver": "bin/semver.js" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/tsup/node_modules/esbuild-openbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/tsup/node_modules/esbuild-sunos-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", + "node_modules/tsup/node_modules/esbuild-windows-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "jsonc-parser": "^3.0.0", - "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sirv": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz", - "integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==", + "node_modules/tsup/node_modules/esbuild-windows-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^3.0.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 10" + "node": ">=12" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/tsup/node_modules/esbuild-windows-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", + "cpu": [ + "arm64" + ], "dev": true, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "node_modules/typedoc": { + "version": "0.23.22", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.22.tgz", + "integrity": "sha512-5sJkjK60xp8A7YpcYniu3+Wf0QcgojEnhzHuCN+CkdpQkKRhOspon/9+sGTkGI8kjVkZs3KHrhltpQyVhRMVfw==", "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.0.19", + "minimatch": "^5.1.0", + "shiki": "^0.11.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x" } }, - "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==", + "node_modules/typedoc-plugin-markdown": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.14.0.tgz", + "integrity": "sha512-UyQLkLRkfTFhLdhSf3RRpA3nNInGn+k6sll2vRXjflaMNwQAAiB61SYbisNZTg16t4K1dt1bPQMMGLrxS0GZ0Q==", "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "handlebars": "^4.7.7" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "typedoc": ">=0.23.0" } }, - "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==", + "node_modules/typedoc/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "balanced-match": "^1.0.0" + } + }, + "node_modules/typedoc/node_modules/minimatch": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", + "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, "engines": { - "node": ">=6" + "node": ">=4.2.0" } }, - "node_modules/sucrase": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.22.0.tgz", - "integrity": "sha512-RZeE0UPxCjf99p4c9Sb27qRbsuZBd7TViR/q1P6TsUPYa/H2LIkaCPpio6F1nQksrynYA78KEBUnpxswZiPYcg==", + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, - "dependencies": { - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, + "optional": true, "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" + "uglifyjs": "bin/uglifyjs" }, "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, - "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "node_modules/ulid": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz", + "integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==", + "bin": { + "ulid": "bin/cli.js" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", + "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10.12.0" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/vite": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", + "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "esbuild": "^0.15.9", + "postcss": "^8.4.18", + "resolve": "^1.22.1", + "rollup": "^2.79.1" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=8" + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "cpu": [ + "loong64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12" } }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/vite/node_modules/esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" + } + }, + "node_modules/vite/node_modules/esbuild-android-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "node_modules/vite/node_modules/esbuild-android-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "any-promise": "^1.0.0" + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" } }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "node_modules/vite/node_modules/esbuild-darwin-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.8" + "node": ">=12" } }, - "node_modules/tinypool": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.2.4.tgz", - "integrity": "sha512-Vs3rhkUH6Qq1t5bqtb816oT+HeJTXfwt2cbPH17sWHIYKTotQIFPk3tf2fgqRrVyMDVOc1EnPgzIxfIulXVzwQ==", + "node_modules/vite/node_modules/esbuild-darwin-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", + "cpu": [ + "arm64" + ], "dev": true, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/tinyspy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-1.0.2.tgz", - "integrity": "sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==", + "node_modules/vite/node_modules/esbuild-freebsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", + "cpu": [ + "x64" + ], "dev": true, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=14.0.0" + "node": ">=12" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/vite/node_modules/esbuild-freebsd-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8.0" + "node": ">=12" } }, - "node_modules/totalist": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz", - "integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==", + "node_modules/vite/node_modules/esbuild-linux-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", + "cpu": [ + "ia32" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "node_modules/vite/node_modules/esbuild-linux-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "punycode": "^2.1.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "node_modules/vite/node_modules/esbuild-linux-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", + "cpu": [ + "arm" + ], "dev": true, - "bin": { - "tree-kill": "cli.js" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true - }, - "node_modules/tsup": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-6.1.2.tgz", - "integrity": "sha512-Hw4hKDHaAQkm2eVavlArEOrAPA93bziRDamdfwaNs0vXQdUUFfItvUWY0L/F6oQQMVh6GvjQq1+HpDXw8UKtPA==", + "node_modules/vite/node_modules/esbuild-linux-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "bundle-require": "^3.0.2", - "cac": "^6.7.12", - "chokidar": "^3.5.1", - "debug": "^4.3.1", - "esbuild": "^0.14.25", - "execa": "^5.0.0", - "globby": "^11.0.3", - "joycon": "^3.0.1", - "postcss-load-config": "^3.0.1", - "resolve-from": "^5.0.0", - "rollup": "^2.74.1", - "source-map": "0.8.0-beta.0", - "sucrase": "^3.20.3", - "tree-kill": "^1.2.2" - }, - "bin": { - "tsup": "dist/cli-default.js", - "tsup-node": "dist/cli-node.js" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@swc/core": "^1", - "postcss": "^8.4.12", - "typescript": "^4.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "postcss": { - "optional": true - }, - "typescript": { - "optional": true - } + "node": ">=12" } }, - "node_modules/tsup/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "node_modules/vite/node_modules/esbuild-linux-mips64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", + "cpu": [ + "mips64el" + ], "dev": true, - "dependencies": { - "whatwg-url": "^7.0.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">=12" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "node_modules/vite/node_modules/esbuild-linux-ppc64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", + "cpu": [ + "ppc64" + ], "dev": true, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/typedoc": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.2.tgz", - "integrity": "sha512-THpC4vtb3wu1yck6YHzEc4ck6W4lScf8TD0Rg7XAetDih8BzP+ErYO0/6DtdzYcZyKkDwEoujkMeWW7CffCbrQ==", + "node_modules/vite/node_modules/esbuild-linux-riscv64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "lunr": "^2.3.9", - "marked": "^4.0.16", - "minimatch": "^5.1.0", - "shiki": "^0.10.1" - }, - "bin": { - "typedoc": "bin/typedoc" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 14.14" - }, - "peerDependencies": { - "typescript": "4.6.x || 4.7.x" + "node": ">=12" } }, - "node_modules/typedoc-plugin-markdown": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.13.1.tgz", - "integrity": "sha512-Gx7pmvFNXAxbE9N2MuQNi5RwMVSH9lPxDBAaBNftaZ+ZzMO8YkDwir6aoXcWNq50qgG/eTs5CiKvLe33OVm2iQ==", + "node_modules/vite/node_modules/esbuild-linux-s390x": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "handlebars": "^4.7.7" - }, - "peerDependencies": { - "typedoc": ">=0.23.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" } }, - "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/vite/node_modules/esbuild-netbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" } }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "node_modules/vite/node_modules/esbuild-openbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "node_modules/vite/node_modules/esbuild-sunos-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", + "cpu": [ + "x64" + ], "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=4.2.0" + "node": ">=12" } }, - "node_modules/uglify-js": { - "version": "3.16.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.1.tgz", - "integrity": "sha512-X5BGTIDH8U6IQ1TIRP62YC36k+ULAa1d59BxlWvPUJ1NkW5L3FwcGfEzuVvGmhJFBu0YJ5Ge25tmRISqCmLiRQ==", + "node_modules/vite/node_modules/esbuild-windows-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", + "cpu": [ + "ia32" + ], "dev": true, "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, + "os": [ + "win32" + ], "engines": { - "node": ">=0.8.0" + "node": ">=12" } }, - "node_modules/ulid": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz", - "integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==", - "bin": { - "ulid": "bin/cli.js" + "node_modules/vite/node_modules/esbuild-windows-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" } }, - "node_modules/v8-to-istanbul": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", + "node_modules/vite/node_modules/esbuild-windows-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10.12.0" + "node": ">=12" } }, - "node_modules/vite": { - "version": "2.9.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.12.tgz", - "integrity": "sha512-suxC36dQo9Rq1qMB2qiRorNJtJAdxguu5TMvBHOc/F370KvqAe9t48vYp+/TbPKRNrMh/J55tOUmkuIqstZaew==", + "node_modules/vite/node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", "dev": true, - "dependencies": { - "esbuild": "^0.14.27", - "postcss": "^8.4.13", - "resolve": "^1.22.0", - "rollup": "^2.59.0" - }, "bin": { - "vite": "bin/vite.js" + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=12.2.0" + "node": ">=10.0.0" }, "optionalDependencies": { "fsevents": "~2.3.2" - }, - "peerDependencies": { - "less": "*", - "sass": "*", - "stylus": "*" - }, - "peerDependenciesMeta": { - "less": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - } } }, "node_modules/vitest": { - "version": "0.20.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.20.3.tgz", - "integrity": "sha512-cXMjTbZxBBUUuIF3PUzEGPLJWtIMeURBDXVxckSHpk7xss4JxkiiWh5cnIlfGyfJne2Ii3QpbiRuFL5dMJtljw==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.25.8.tgz", + "integrity": "sha512-X75TApG2wZTJn299E/TIYevr4E9/nBo1sUtZzn0Ci5oK8qnpZAZyhwg0qCeMSakGIWtc6oRwcQFyFfW14aOFWg==", "dev": true, "dependencies": { - "@types/chai": "^4.3.1", + "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "chai": "^4.3.6", + "acorn": "^8.8.1", + "acorn-walk": "^8.2.0", + "chai": "^4.3.7", "debug": "^4.3.4", "local-pkg": "^0.4.2", - "tinypool": "^0.2.4", - "tinyspy": "^1.0.0", - "vite": "^2.9.12 || ^3.0.0-0" + "source-map": "^0.6.1", + "strip-literal": "^1.0.0", + "tinybench": "^2.3.1", + "tinypool": "^0.3.0", + "tinyspy": "^1.0.2", + "vite": "^3.0.0 || ^4.0.0" }, "bin": { "vitest": "vitest.mjs" @@ -2395,7 +3279,6 @@ "@edge-runtime/vm": "*", "@vitest/browser": "*", "@vitest/ui": "*", - "c8": "*", "happy-dom": "*", "jsdom": "*" }, @@ -2409,9 +3292,6 @@ "@vitest/ui": { "optional": true }, - "c8": { - "optional": true - }, "happy-dom": { "optional": true }, @@ -2420,16 +3300,25 @@ } } }, + "node_modules/vitest/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/vscode-oniguruma": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", "dev": true }, "node_modules/vscode-textmate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz", + "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==", "dev": true }, "node_modules/webidl-conversions": { @@ -2563,6 +3452,181 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.5.tgz", + "integrity": "sha512-BCWkmAqFoW6xXzz6Up16bU0vdZqe23UxkrabbrmXXUuH27Tts3LVcHFCi/dGLYa6ZqC/txhtJm2kAJdoyOfHxg==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/android-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.5.tgz", + "integrity": "sha512-E0R7d0dy9+QlpMps8gJXXhtfn+fQFaTXbq8kV2u/HfHyyhxr4nIIuXZCcYxxA9LSKnsFBBbSQIGDUVY9FGgx0w==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/darwin-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.5.tgz", + "integrity": "sha512-4HlbUMy50cRaHGVriBjShs46WRPshtnVOqkxEGhEuDuJhgZ3regpWzaQxXOcDXFvVwue8RiqDAAcOi/QlVLE6Q==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/darwin-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.5.tgz", + "integrity": "sha512-ZDCAxAPwbtKJ5YxRZusQKDFuywH+7YNKbilss0DCRPtXMxrKRZETcuSfcgIWGYBBc+ypdOazousx3yZss2Az0A==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.5.tgz", + "integrity": "sha512-w0dJ8om4KiagLCHURgwxXVWzi5xa0W7F5woMxzWO+LDCebrlyZUhCIbSXUKa4qD3XbdG7K4Y8N4mLDRMkZzMuw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/freebsd-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.5.tgz", + "integrity": "sha512-qCdC0T7XUxngX8otO4nmPUE/cHZfvF8jk+GMr9qkAGP0nIMACD7t/AWoY2N5rsn5/dOJ1VKM/aMF4wCFBP5AqQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-arm": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.5.tgz", + "integrity": "sha512-6crdpqwFjl+DObBgwaJMtB+VWrZd87Jy05gQTERysc1ujnUJNCJzemUcRDT5hM34dzTYThlXfFW32qQy9QpPGQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.5.tgz", + "integrity": "sha512-h84QZmBhBdEclyxf9Wm/UESY6ITI7/gYLNvj/3emhDd0ILAqwHdWnMDmKqqubrMcpb1O4sWOYRm7EZ+Av8eGiQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-ia32": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.5.tgz", + "integrity": "sha512-P1WNzGqy6ipvbt8iNoYY66+qUANCiM80D8bGJIU8jqSZ613eG0lUWBePi4xQazcNgIi9tSiCa9Ba3f4krXtQDw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-loong64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.5.tgz", + "integrity": "sha512-r8wKqs+rl4gIT/xDB6CHMaYcvvyZ7tWf5LulH9NsDvgQEy3gIXQPR4Oy9tYrjM75uKkvBv1uw15Iz4EWsvve9Q==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-mips64el": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.5.tgz", + "integrity": "sha512-0WMhOlwfeeAp6KMx3E6LZKDN6INk4Me8dwIw1XMSFvmE6r31vRnwXkrQlAk5FI44KZ/rIi+yynRZqEd7UJAV2g==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-ppc64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.5.tgz", + "integrity": "sha512-29x+DtRGcYH0Sh3QSnoF+D2SYkHLxwx5AugoGLIlVtcVqDb4fEb654d67k9VcAR2RiTAYUZ764KXzWB+ItQfgw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-riscv64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.5.tgz", + "integrity": "sha512-ZX4SSKOJUcuqFNDydfN4yCo9je9f1T72Pj+RLsAGRiuiREVCwRkXIBp810C01+MdPqYExp322kY78ISEq5XGLQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-s390x": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.5.tgz", + "integrity": "sha512-pYY86RiLD1s5RN8q0aMhWD44NiHmAZxv2bSzaNlL63/ibWETld+m6F+MPh9+ZNOqGJw53E/0qHukYI5Lm+1k7A==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.5.tgz", + "integrity": "sha512-vsOwzKN+4NenUTyuoWLmg5dAuO8JKuLD9MXSeENA385XucuOZbblmOMwwgPlHsgVRtSjz38riqPJU2ALI/CWYQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/netbsd-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.5.tgz", + "integrity": "sha512-ZhfELxpZLXg7OidX9MrjgQNhjhYx3GXm59EAQVZds8GTyOOPj+Hg7ttKenlXoV8PZVkoCm0dgoWXzhasZJGfWw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/openbsd-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.5.tgz", + "integrity": "sha512-2HY2L0afN8IUgvxCAWY04bB6mhHSnC7YNGM2hmEkyAgP+n8jpZgGjiRokuk3AQ0g0IpX8h0KnS+xaznGEr5CGw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/sunos-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.5.tgz", + "integrity": "sha512-Q7+HbDnW52LLW8YIU5h0sYZ23TvaaC0vuwiIbJUa91Qr77NKNJCe8stfunN1TRZo+6OwGpM3MrdUcUVUfr5wuA==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/win32-arm64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.5.tgz", + "integrity": "sha512-KcegNS7IgLm/cAcjIW3kZyLiZi/p8I+A2a6OonDA77em9xHewdA2yTA+9pO4gr77MkXATcnDAFBrWw5oLHIZkQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/win32-ia32": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.5.tgz", + "integrity": "sha512-ReUCJSzLNGH6WcvwjMzpEy2SX5GTZBeRTvCdklN4DT2YrgRIe82lYVikVHwA7fdiL3xHKvmdiicMqxE8QYmxrA==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/win32-x64": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.5.tgz", + "integrity": "sha512-q00Jasz6/wCOD2XxRj4GEwj27u1zfpiBniL1ip3/YGGcYtvOoGKCNSS47sufO/8ixEgrSYDlkglSd6CxcS7m0g==", + "dev": true, + "optional": true, + "peer": true + }, "@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", @@ -2570,25 +3634,25 @@ "dev": true }, "@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "@nodelib/fs.scandir": { @@ -2624,49 +3688,49 @@ "dev": true }, "@redis/bloom": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.0.2.tgz", - "integrity": "sha512-EBw7Ag1hPgFzdznK2PBblc1kdlj5B5Cw3XwI9/oG7tSn85/HKy3X9xHy/8tm/eNXJYHLXHJL/pkwBpFMVVefkw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.1.0.tgz", + "integrity": "sha512-9QovlxmpRtvxVbN0UBcv8WfdSMudNZZTFqCsnBszcQXqaZb/TVe30ScgGEO7u1EAIacTPAo7/oCYjYAxiHLanQ==", "requires": {} }, "@redis/client": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.2.0.tgz", - "integrity": "sha512-a8Nlw5fv2EIAFJxTDSSDVUT7yfBGpZO96ybZXzQpgkyLg/dxtQ1uiwTc0EGfzg1mrPjZokeBSEGTbGXekqTNOg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.4.2.tgz", + "integrity": "sha512-oUdEjE0I7JS5AyaAjkD3aOXn9NhO7XKyPyXEyrgFDu++VrVBHUPnV6dgEya9TcMuj5nIJRuCzCm8ZP+c9zCHPw==", "requires": { - "cluster-key-slot": "1.1.0", - "generic-pool": "3.8.2", + "cluster-key-slot": "1.1.1", + "generic-pool": "3.9.0", "yallist": "4.0.0" } }, "@redis/graph": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.0.1.tgz", - "integrity": "sha512-oDE4myMCJOCVKYMygEMWuriBgqlS5FqdWerikMoJxzmmTUErnTRRgmIDa2VcgytACZMFqpAOWDzops4DOlnkfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", "requires": {} }, "@redis/json": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.3.tgz", - "integrity": "sha512-4X0Qv0BzD9Zlb0edkUoau5c1bInWSICqXAGrpwEltkncUwcxJIGEcVryZhLgb0p/3PkKaLIWkjhHRtLe9yiA7Q==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", "requires": {} }, "@redis/search": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.0.6.tgz", - "integrity": "sha512-pP+ZQRis5P21SD6fjyCeLcQdps+LuTzp2wdUbzxEmNhleighDDTD5ck8+cYof+WLec4csZX7ks+BuoMw0RaZrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.0.tgz", + "integrity": "sha512-NyFZEVnxIJEybpy+YskjgOJRNsfTYqaPbK/Buv6W2kmFNaRk85JiqjJZA5QkRmWvGbyQYwoO5QfDi2wHskKrQQ==", "requires": {} }, "@redis/time-series": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.3.tgz", - "integrity": "sha512-OFp0q4SGrTH0Mruf6oFsHGea58u8vS/iI5+NpYdicaM+7BgqBZH8FFvNZ8rYYLrUO/QRqMq72NpXmxLVNcdmjA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", "requires": {} }, "@types/chai": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", - "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", "dev": true }, "@types/chai-subset": { @@ -2685,20 +3749,32 @@ "dev": true }, "@types/node": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.0.tgz", - "integrity": "sha512-cHlGmko4gWLVI27cGJntjs/Sj8th9aYwplmZFwmmgYQQvL5NUsgVJG7OddLvNfLqYS31KFN0s3qlaD9qCaxACA==", + "version": "18.11.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.14.tgz", + "integrity": "sha512-0KXV57tENYmmJMl+FekeW9V3O/rlcqGQQJ/hNh9r8pKIj304pskWuEd8fCyNT86g/TpO0gcOTiLzsHLEURFMIQ==", "dev": true }, "@vitest/ui": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.17.1.tgz", - "integrity": "sha512-B4PGDk5IZ10HT9GzR0NQ96VEphWY9dTf1yqBGNjPk2c7wQnhZJdHzv3tgFQiyFK5YR1cjtOV918QHCnptV4r5w==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.25.8.tgz", + "integrity": "sha512-wfuhghldD5QHLYpS46GK8Ru8P3XcMrWvFjRQD21KNzc9Y/qtJsqoC8KmT6xWVkMNw4oHYixpo3a4ZySRJdserw==", "dev": true, "requires": { "sirv": "^2.0.2" } }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2721,9 +3797,9 @@ "dev": true }, "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -2774,18 +3850,18 @@ } }, "bundle-require": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-3.0.4.tgz", - "integrity": "sha512-VXG6epB1yrLAvWVQpl92qF347/UXmncQj7J3U8kZEbdVZ1ZkQyr4hYeL/9RvcE8vVVdp53dY78Fd/3pqfRqI1A==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-3.1.2.tgz", + "integrity": "sha512-Of6l6JBAxiyQ5axFxUM6dYeP/W7X2Sozeo/4EYB9sJhL+dqL7TKjg+shwxp6jlu/6ZSERfsYtIpSJ1/x3XkAEA==", "dev": true, "requires": { "load-tsconfig": "^0.2.0" } }, "c8": { - "version": "7.11.3", - "resolved": "https://registry.npmjs.org/c8/-/c8-7.11.3.tgz", - "integrity": "sha512-6YBmsaNmqRm9OS3ZbIiL2EZgi1+Xc4O24jL3vMYGE6idixYuGdy76rIfIdltSKDj9DpLNrcXSonUTR1miBD0wA==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/c8/-/c8-7.12.0.tgz", + "integrity": "sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", @@ -2803,20 +3879,20 @@ } }, "cac": { - "version": "6.7.12", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.12.tgz", - "integrity": "sha512-rM7E2ygtMkJqD9c7WnFU6fruFcN3xe4FM5yUmgxhZzIKJk4uHl9U/fhwdajGFQbQuv43FAUo1Fe8gX/oIKDeSA==", + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true }, "chai": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", - "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", "dev": true, "requires": { "assertion-error": "^1.1.0", "check-error": "^1.0.2", - "deep-eql": "^3.0.1", + "deep-eql": "^4.1.2", "get-func-name": "^2.0.0", "loupe": "^2.3.1", "pathval": "^1.1.1", @@ -2857,9 +3933,9 @@ } }, "cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==" }, "color-convert": { "version": "2.0.1", @@ -2889,13 +3965,10 @@ "dev": true }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "cross-spawn": { "version": "7.0.3", @@ -2918,9 +3991,9 @@ } }, "deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", "dev": true, "requires": { "type-detect": "^4.0.0" @@ -2942,172 +4015,45 @@ "dev": true }, "esbuild": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.48.tgz", - "integrity": "sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==", + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.5.tgz", + "integrity": "sha512-te0zG5CDzAxhnBKeddXUtK8xDnYL6jv100ekldhtUk0ALXPXcDAtuH0fAR7rbKwUdz3bOey6HVq2N+aWCKZ1cw==", "dev": true, + "peer": true, "requires": { - "esbuild-android-64": "0.14.48", - "esbuild-android-arm64": "0.14.48", - "esbuild-darwin-64": "0.14.48", - "esbuild-darwin-arm64": "0.14.48", - "esbuild-freebsd-64": "0.14.48", - "esbuild-freebsd-arm64": "0.14.48", - "esbuild-linux-32": "0.14.48", - "esbuild-linux-64": "0.14.48", - "esbuild-linux-arm": "0.14.48", - "esbuild-linux-arm64": "0.14.48", - "esbuild-linux-mips64le": "0.14.48", - "esbuild-linux-ppc64le": "0.14.48", - "esbuild-linux-riscv64": "0.14.48", - "esbuild-linux-s390x": "0.14.48", - "esbuild-netbsd-64": "0.14.48", - "esbuild-openbsd-64": "0.14.48", - "esbuild-sunos-64": "0.14.48", - "esbuild-windows-32": "0.14.48", - "esbuild-windows-64": "0.14.48", - "esbuild-windows-arm64": "0.14.48" - } - }, - "esbuild-android-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.48.tgz", - "integrity": "sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==", - "dev": true, - "optional": true - }, - "esbuild-android-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.48.tgz", - "integrity": "sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==", - "dev": true, - "optional": true - }, - "esbuild-darwin-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.48.tgz", - "integrity": "sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==", - "dev": true, - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.48.tgz", - "integrity": "sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.48.tgz", - "integrity": "sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==", - "dev": true, - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.48.tgz", - "integrity": "sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==", - "dev": true, - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.48.tgz", - "integrity": "sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.48.tgz", - "integrity": "sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.48.tgz", - "integrity": "sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==", - "dev": true, - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.48.tgz", - "integrity": "sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==", - "dev": true, - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.48.tgz", - "integrity": "sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==", - "dev": true, - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.48.tgz", - "integrity": "sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==", - "dev": true, - "optional": true - }, - "esbuild-linux-riscv64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.48.tgz", - "integrity": "sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==", - "dev": true, - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.48.tgz", - "integrity": "sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==", - "dev": true, - "optional": true - }, - "esbuild-netbsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.48.tgz", - "integrity": "sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==", - "dev": true, - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.48.tgz", - "integrity": "sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==", - "dev": true, - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.48.tgz", - "integrity": "sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==", - "dev": true, - "optional": true - }, - "esbuild-windows-32": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.48.tgz", - "integrity": "sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==", - "dev": true, - "optional": true - }, - "esbuild-windows-64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.48.tgz", - "integrity": "sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==", - "dev": true, - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.48", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.48.tgz", - "integrity": "sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==", - "dev": true, - "optional": true + "@esbuild/android-arm": "0.16.5", + "@esbuild/android-arm64": "0.16.5", + "@esbuild/android-x64": "0.16.5", + "@esbuild/darwin-arm64": "0.16.5", + "@esbuild/darwin-x64": "0.16.5", + "@esbuild/freebsd-arm64": "0.16.5", + "@esbuild/freebsd-x64": "0.16.5", + "@esbuild/linux-arm": "0.16.5", + "@esbuild/linux-arm64": "0.16.5", + "@esbuild/linux-ia32": "0.16.5", + "@esbuild/linux-loong64": "0.16.5", + "@esbuild/linux-mips64el": "0.16.5", + "@esbuild/linux-ppc64": "0.16.5", + "@esbuild/linux-riscv64": "0.16.5", + "@esbuild/linux-s390x": "0.16.5", + "@esbuild/linux-x64": "0.16.5", + "@esbuild/netbsd-x64": "0.16.5", + "@esbuild/openbsd-x64": "0.16.5", + "@esbuild/sunos-x64": "0.16.5", + "@esbuild/win32-arm64": "0.16.5", + "@esbuild/win32-ia32": "0.16.5", + "@esbuild/win32-x64": "0.16.5" + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.16.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.5.tgz", + "integrity": "sha512-eNkNuLSKpbZTH0BZklJ9B9Sml7fTIamhrQNBwftsEHCUuSLBVunzV3LfghryVGpE5lSkOwOfeX6gR6+3yLaEfQ==", + "dev": true, + "optional": true, + "peer": true + } + } }, "escalade": { "version": "3.1.1", @@ -3130,20 +4076,12 @@ "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - } } }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -3154,9 +4092,9 @@ } }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -3211,9 +4149,9 @@ "dev": true }, "generic-pool": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.8.2.tgz", - "integrity": "sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg==" + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" }, "get-caller-file": { "version": "2.0.5", @@ -3227,6 +4165,12 @@ "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", "dev": true }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3275,6 +4219,14 @@ "source-map": "^0.6.1", "uglify-js": "^3.1.4", "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "has": { @@ -3305,9 +4257,9 @@ "dev": true }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true }, "inflight": { @@ -3336,9 +4288,9 @@ } }, "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -3417,15 +4369,15 @@ "dev": true }, "jsonc-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", - "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, "lilconfig": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz", - "integrity": "sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", "dev": true }, "lines-and-columns": { @@ -3462,9 +4414,9 @@ "dev": true }, "loupe": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", - "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", "dev": true, "requires": { "get-func-name": "^2.0.0" @@ -3486,9 +4438,9 @@ } }, "marked": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz", - "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.4.tgz", + "integrity": "sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==", "dev": true }, "merge-stream": { @@ -3529,9 +4481,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "mrmime": { @@ -3681,9 +4633,9 @@ "dev": true }, "postcss": { - "version": "8.4.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", - "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", "dev": true, "requires": { "nanoid": "^3.3.4", @@ -3723,16 +4675,16 @@ } }, "redis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.2.0.tgz", - "integrity": "sha512-bCR0gKVhIXFg8zCQjXEANzgI01DDixtPZgIUZHBCmwqixnu+MK3Tb2yqGjh+HCLASQVVgApiwhNkv+FoedZOGQ==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.5.1.tgz", + "integrity": "sha512-oxXSoIqMJCQVBTfxP6BNTCtDMyh9G6Vi5wjdPdV/sRKkufyZslDqCScSGcOr6XGR/reAWZefz7E4leM31RgdBA==", "requires": { - "@redis/bloom": "1.0.2", - "@redis/client": "1.2.0", - "@redis/graph": "1.0.1", - "@redis/json": "1.0.3", - "@redis/search": "1.0.6", - "@redis/time-series": "1.0.3" + "@redis/bloom": "1.1.0", + "@redis/client": "1.4.2", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.0", + "@redis/time-series": "1.0.4" } }, "require-directory": { @@ -3774,9 +4726,9 @@ } }, "rollup": { - "version": "2.75.7", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.7.tgz", - "integrity": "sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.4.tgz", + "integrity": "sha512-jN9rx3k5pfg9H9al0r0y1EYKSeiRANZRYX32SuNXAnKzh6cVyf4LZVto1KAuDnbHT03E1CpsgqDKaqQ8FZtgxw==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -3791,12 +4743,6 @@ "queue-microtask": "^1.2.2" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -3819,14 +4765,14 @@ "dev": true }, "shiki": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.10.1.tgz", - "integrity": "sha512-VsY7QJVzU51j5o1+DguUd+6vmCmZ5v/6gYu4vyYAhzjuNQU6P/vmSy4uQaOhvje031qQMiW0d2BwgMH52vqMng==", + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz", + "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==", "dev": true, "requires": { "jsonc-parser": "^3.0.0", "vscode-oniguruma": "^1.6.1", - "vscode-textmate": "5.2.0" + "vscode-textmate": "^6.0.0" } }, "signal-exit": { @@ -3853,10 +4799,13 @@ "dev": true }, "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dev": true, + "requires": { + "whatwg-url": "^7.0.0" + } }, "source-map-js": { "version": "1.0.2", @@ -3890,10 +4839,19 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strip-literal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.0.tgz", + "integrity": "sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==", + "dev": true, + "requires": { + "acorn": "^8.8.1" + } + }, "sucrase": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.22.0.tgz", - "integrity": "sha512-RZeE0UPxCjf99p4c9Sb27qRbsuZBd7TViR/q1P6TsUPYa/H2LIkaCPpio6F1nQksrynYA78KEBUnpxswZiPYcg==", + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.29.0.tgz", + "integrity": "sha512-bZPAuGA5SdFHuzqIhTAqt9fvNEo9rESqXIG3oiKdF8K4UmkQxC4KlNL3lVyAErXp+mPvUqZ5l13qx6TrDIGf3A==", "dev": true, "requires": { "commander": "^4.0.0", @@ -3964,10 +4922,16 @@ "thenify": ">= 3.1.0 < 4" } }, + "tinybench": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.3.1.tgz", + "integrity": "sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==", + "dev": true + }, "tinypool": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.2.4.tgz", - "integrity": "sha512-Vs3rhkUH6Qq1t5bqtb816oT+HeJTXfwt2cbPH17sWHIYKTotQIFPk3tf2fgqRrVyMDVOc1EnPgzIxfIulXVzwQ==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.0.tgz", + "integrity": "sha512-NX5KeqHOBZU6Bc0xj9Vr5Szbb1j8tUHIeD18s41aDJaPeC5QTdEhK0SpdpUrZlj2nv5cctNcSjaKNanXlfcVEQ==", "dev": true }, "tinyspy": { @@ -4013,35 +4977,203 @@ "dev": true }, "tsup": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-6.1.2.tgz", - "integrity": "sha512-Hw4hKDHaAQkm2eVavlArEOrAPA93bziRDamdfwaNs0vXQdUUFfItvUWY0L/F6oQQMVh6GvjQq1+HpDXw8UKtPA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-6.5.0.tgz", + "integrity": "sha512-36u82r7rYqRHFkD15R20Cd4ercPkbYmuvRkz3Q1LCm5BsiFNUgpo36zbjVhCOgvjyxNBWNKHsaD5Rl8SykfzNA==", "dev": true, "requires": { - "bundle-require": "^3.0.2", + "bundle-require": "^3.1.2", "cac": "^6.7.12", "chokidar": "^3.5.1", "debug": "^4.3.1", - "esbuild": "^0.14.25", + "esbuild": "^0.15.1", "execa": "^5.0.0", "globby": "^11.0.3", "joycon": "^3.0.1", "postcss-load-config": "^3.0.1", "resolve-from": "^5.0.0", - "rollup": "^2.74.1", + "rollup": "^3.2.5", "source-map": "0.8.0-beta.0", "sucrase": "^3.20.3", "tree-kill": "^1.2.2" }, "dependencies": { - "source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "dev": true, + "optional": true + }, + "esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", "dev": true, "requires": { - "whatwg-url": "^7.0.0" + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } + }, + "esbuild-android-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", + "dev": true, + "optional": true } } }, @@ -4052,15 +5184,15 @@ "dev": true }, "typedoc": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.2.tgz", - "integrity": "sha512-THpC4vtb3wu1yck6YHzEc4ck6W4lScf8TD0Rg7XAetDih8BzP+ErYO0/6DtdzYcZyKkDwEoujkMeWW7CffCbrQ==", + "version": "0.23.22", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.22.tgz", + "integrity": "sha512-5sJkjK60xp8A7YpcYniu3+Wf0QcgojEnhzHuCN+CkdpQkKRhOspon/9+sGTkGI8kjVkZs3KHrhltpQyVhRMVfw==", "dev": true, "requires": { "lunr": "^2.3.9", - "marked": "^4.0.16", + "marked": "^4.0.19", "minimatch": "^5.1.0", - "shiki": "^0.10.1" + "shiki": "^0.11.1" }, "dependencies": { "brace-expansion": { @@ -4073,9 +5205,9 @@ } }, "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", + "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -4084,24 +5216,24 @@ } }, "typedoc-plugin-markdown": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.13.1.tgz", - "integrity": "sha512-Gx7pmvFNXAxbE9N2MuQNi5RwMVSH9lPxDBAaBNftaZ+ZzMO8YkDwir6aoXcWNq50qgG/eTs5CiKvLe33OVm2iQ==", + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.14.0.tgz", + "integrity": "sha512-UyQLkLRkfTFhLdhSf3RRpA3nNInGn+k6sll2vRXjflaMNwQAAiB61SYbisNZTg16t4K1dt1bPQMMGLrxS0GZ0Q==", "dev": true, "requires": { "handlebars": "^4.7.7" } }, "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true }, "uglify-js": { - "version": "3.16.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.16.1.tgz", - "integrity": "sha512-X5BGTIDH8U6IQ1TIRP62YC36k+ULAa1d59BxlWvPUJ1NkW5L3FwcGfEzuVvGmhJFBu0YJ5Ge25tmRISqCmLiRQ==", + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, "optional": true }, @@ -4122,45 +5254,246 @@ } }, "vite": { - "version": "2.9.12", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.9.12.tgz", - "integrity": "sha512-suxC36dQo9Rq1qMB2qiRorNJtJAdxguu5TMvBHOc/F370KvqAe9t48vYp+/TbPKRNrMh/J55tOUmkuIqstZaew==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz", + "integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==", "dev": true, "requires": { - "esbuild": "^0.14.27", + "esbuild": "^0.15.9", "fsevents": "~2.3.2", - "postcss": "^8.4.13", - "resolve": "^1.22.0", - "rollup": "^2.59.0" + "postcss": "^8.4.18", + "resolve": "^1.22.1", + "rollup": "^2.79.1" + }, + "dependencies": { + "@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "dev": true, + "optional": true + }, + "esbuild": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" + } + }, + "esbuild-android-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", + "dev": true, + "optional": true + }, + "esbuild-windows-32": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", + "dev": true, + "optional": true + }, + "rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + } } }, "vitest": { - "version": "0.20.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.20.3.tgz", - "integrity": "sha512-cXMjTbZxBBUUuIF3PUzEGPLJWtIMeURBDXVxckSHpk7xss4JxkiiWh5cnIlfGyfJne2Ii3QpbiRuFL5dMJtljw==", + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.25.8.tgz", + "integrity": "sha512-X75TApG2wZTJn299E/TIYevr4E9/nBo1sUtZzn0Ci5oK8qnpZAZyhwg0qCeMSakGIWtc6oRwcQFyFfW14aOFWg==", "dev": true, "requires": { - "@types/chai": "^4.3.1", + "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "chai": "^4.3.6", + "acorn": "^8.8.1", + "acorn-walk": "^8.2.0", + "chai": "^4.3.7", "debug": "^4.3.4", "local-pkg": "^0.4.2", - "tinypool": "^0.2.4", - "tinyspy": "^1.0.0", - "vite": "^2.9.12 || ^3.0.0-0" + "source-map": "^0.6.1", + "strip-literal": "^1.0.0", + "tinybench": "^2.3.1", + "tinypool": "^0.3.0", + "tinyspy": "^1.0.2", + "vite": "^3.0.0 || ^4.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "vscode-oniguruma": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz", - "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", "dev": true }, "vscode-textmate": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-5.2.0.tgz", - "integrity": "sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz", + "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==", "dev": true }, "webidl-conversions": { diff --git a/package.json b/package.json index f6a1c529..16f9c6d6 100644 --- a/package.json +++ b/package.json @@ -44,17 +44,16 @@ }, "devDependencies": { "@types/node": "^18.0.0", - "@vitest/ui": "^0.17.1", + "@vitest/ui": "^0.25.0", "c8": "^7.11.3", - "esbuild": "^0.14.48", "tsup": "^6.1.2", "typedoc": "^0.23.2", "typedoc-plugin-markdown": "^3.13.1", "typescript": "^4.7.2", - "vitest": "^0.20.0" + "vitest": "^0.25.0" }, "dependencies": { "redis": "^4.2.0", "ulid": "^2.3.0" } -} +} \ No newline at end of file diff --git a/vitest.config.js b/vitest.config.js index 8c088788..dfdfa5c2 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -1,24 +1,21 @@ import { defineConfig } from 'vitest/config' -import path from "path" +import path from 'path' export default defineConfig({ - test: { - globals: true, - clearMocks: true, - isolate: false, - coverage: { - provider: 'istanbul', - exclude: [ - 'spec/*' - ] - }, - exclude: [ - './node_modules/**', - ] - }, - resolve: { - alias: { - "$lib": path.resolve(__dirname, "./lib"), - }, - }, -}) \ No newline at end of file + test: { + globals: true, + clearMocks: true, + isolate: true, + threads: true, + coverage: { + provider: 'istanbul', + exclude: ['spec/*'], + }, + exclude: ['./node_modules/**'], + }, + resolve: { + alias: { + $lib: path.resolve(__dirname, './lib'), + }, + }, +}) From eaa376347c426456ff9c44163f08dc959350bb51 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Tue, 13 Dec 2022 11:51:54 -0700 Subject: [PATCH 26/28] configure coverage for latest vitest --- package-lock.json | 24 ++++++++++++++++++++++++ package.json | 3 ++- vitest.config.js | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 985b9fbb..30de5fb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ }, "devDependencies": { "@types/node": "^18.0.0", + "@vitest/coverage-c8": "^0.25.8", "@vitest/ui": "^0.25.0", "c8": "^7.11.3", "tsup": "^6.1.2", @@ -560,6 +561,19 @@ "integrity": "sha512-0KXV57tENYmmJMl+FekeW9V3O/rlcqGQQJ/hNh9r8pKIj304pskWuEd8fCyNT86g/TpO0gcOTiLzsHLEURFMIQ==", "dev": true }, + "node_modules/@vitest/coverage-c8": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-c8/-/coverage-c8-0.25.8.tgz", + "integrity": "sha512-fWgzQoK2KNzTTNnDcLCyibfO9/pbcpPOMtZ9Yvq/Eggpi2X8lewx/OcKZkO5ba5q9dl6+BBn6d5hTcS1709rZw==", + "dev": true, + "dependencies": { + "c8": "^7.12.0", + "vitest": "0.25.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@vitest/ui": { "version": "0.25.8", "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.25.8.tgz", @@ -3754,6 +3768,16 @@ "integrity": "sha512-0KXV57tENYmmJMl+FekeW9V3O/rlcqGQQJ/hNh9r8pKIj304pskWuEd8fCyNT86g/TpO0gcOTiLzsHLEURFMIQ==", "dev": true }, + "@vitest/coverage-c8": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@vitest/coverage-c8/-/coverage-c8-0.25.8.tgz", + "integrity": "sha512-fWgzQoK2KNzTTNnDcLCyibfO9/pbcpPOMtZ9Yvq/Eggpi2X8lewx/OcKZkO5ba5q9dl6+BBn6d5hTcS1709rZw==", + "dev": true, + "requires": { + "c8": "^7.12.0", + "vitest": "0.25.8" + } + }, "@vitest/ui": { "version": "0.25.8", "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.25.8.tgz", diff --git a/package.json b/package.json index 16f9c6d6..63e671a8 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ }, "devDependencies": { "@types/node": "^18.0.0", + "@vitest/coverage-c8": "^0.25.8", "@vitest/ui": "^0.25.0", "c8": "^7.11.3", "tsup": "^6.1.2", @@ -56,4 +57,4 @@ "redis": "^4.2.0", "ulid": "^2.3.0" } -} \ No newline at end of file +} diff --git a/vitest.config.js b/vitest.config.js index dfdfa5c2..0f4478e5 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -8,7 +8,7 @@ export default defineConfig({ isolate: true, threads: true, coverage: { - provider: 'istanbul', + provider: 'c8', exclude: ['spec/*'], }, exclude: ['./node_modules/**'], From 07a9861c263d3edd40aae8c35bb784d21550420b Mon Sep 17 00:00:00 2001 From: Simon Green Date: Tue, 13 Dec 2022 11:54:27 -0700 Subject: [PATCH 27/28] update node-redis --- package-lock.json | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 30de5fb0..90e4ef0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.3.6", "license": "MIT", "dependencies": { - "redis": "^4.2.0", + "redis": "^4.5.0", "ulid": "^2.3.0" }, "devDependencies": { diff --git a/package.json b/package.json index 63e671a8..e7112737 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "vitest": "^0.25.0" }, "dependencies": { - "redis": "^4.2.0", + "redis": "^4.5.0", "ulid": "^2.3.0" } -} +} \ No newline at end of file From ff0800a264df745a8f3c9e6de7db99198fee5188 Mon Sep 17 00:00:00 2001 From: Simon Green Date: Tue, 13 Dec 2022 16:06:47 -0700 Subject: [PATCH 28/28] working HASH + JSON vector search --- lib/entity/fields/entity-binary-field.ts | 8 +- spec/functional/search/products.ts | 22 ++++ spec/functional/search/vector-hash.spec.ts | 98 +++++++++++++++++ spec/functional/search/vector-json.spec.ts | 98 +++++++++++++++++ spec/functional/vector.spec.ts | 118 --------------------- spec/helpers/example-data.ts | 4 +- 6 files changed, 226 insertions(+), 122 deletions(-) create mode 100644 spec/functional/search/products.ts create mode 100644 spec/functional/search/vector-hash.spec.ts create mode 100644 spec/functional/search/vector-json.spec.ts delete mode 100644 spec/functional/vector.spec.ts diff --git a/lib/entity/fields/entity-binary-field.ts b/lib/entity/fields/entity-binary-field.ts index b9802437..55e1a38f 100644 --- a/lib/entity/fields/entity-binary-field.ts +++ b/lib/entity/fields/entity-binary-field.ts @@ -5,7 +5,11 @@ import { EntityValue } from "../entity-value"; export class EntityBinaryField extends EntityField { toRedisJson(): RedisJsonData { const data: RedisJsonData = {}; - if (this.value !== null) data[this.name] = [...this.valueAsBuffer] + if (this.value !== null) { + const bytes = this.valueAsBuffer + const arr = new Float32Array(bytes.buffer, bytes.byteOffset, bytes.length / Float32Array.BYTES_PER_ELEMENT) + data[this.name] = [...arr] + } return data; } @@ -13,7 +17,7 @@ export class EntityBinaryField extends EntityField { if (!this.isBuffer(value)) { throw Error(`Non-binary value of '${value}' read from Redis for binary field.`) } - this.value = Buffer.from([...value]); + this.value = value } toRedisHash(): RedisHashData { diff --git a/spec/functional/search/products.ts b/spec/functional/search/products.ts new file mode 100644 index 00000000..5cf6a755 --- /dev/null +++ b/spec/functional/search/products.ts @@ -0,0 +1,22 @@ +// Vector values taken from RedisInsight example (hex format to make comparing bytes with CLI slightly easier) +export const products = [{ + name: 'Mobile phone cover', + price: 50, + image: `55cb1d40f7d0853e18b63d3d120c913fd182893e323a703eac4efb3e8891213e520a03405d2a423d44fcc03e6bed1d3f48eaa43b0a5d863fd153bc3f4d8a023f000000004189713f41ef543ea1f74a3c434fc63ed24b5c3e92559c3db4066b3f6ff9c63e4920883c565b443efb7c063f000000001288fc3ee264d23f000000007303de3af93a1a3fc10fc73e00000000000000001f52403fc3c7fc3f03a7463f6a61813fe613d73c9132ce3f77ee093f794ac03fca66c73fc0b35d3f00000000cab1d63f4b08853fdb93f33d30b08d3ed9bc943cfdb7203c0803c53fe33f633f00000000a5a9963e524c7c3f2104253fe9db8e3e466a893db8c60a3f4032a33ffd9c583f00000000fb631f3f0e50383d7847223f7f5a5a3d9a5cea3ef0092540c341833ba534833c22a2333f28e6ba3e8a401b3f9b66a23b92336e3f2c8c9d3fcec1e43f744157404ef16a3f8a63393e4c422e3d00000000ffacd53eacf1803ec6de1f3f636aa03af052bd3e11c0bc3f1a24f33d437b043ea244a03e98a78b3dd86008407724a03e3f0a333dd676fb3d79ffd93d747c143f1f1ac83a874df33fe1f69b3f72cd9b409b945e3e3bd9043d6c12a13f186de03dc9ec293c1b83cf3d917a9d3d30b6513df375ec3d884c943d773f733db45ae13c6aee8e3eb7aa333fe8c64c3f6a97143f700d5e3cb63a483e2296393c0000000014703d3f94198f3e18c7153e7d2c4e3e323b413f54123f3d1026223de82f6f3d6a9d2e3fe2078d3f3796d33fadd6973e7b249a3c6f86413eb41e8f3e3d662d3f5123cd3ec1fd343f0498533fc48aff3dc8bf4f3ef64e3540dd13163eaa80143f5f70683ea7dee23faae9d13ec90d903fd62e173fc942db3c3203f23e68d03e3f6557793f6e37893f0330b23dea1f7f3e1f8e343e4ae1ca3eb21a303ffd6adf3e37c6003f0000000099f2213e922acd3e3736cd3e7d776b3f5ab7993d16f5453df6d5133bf4f0a53f6112343ef250d83dff01813f817b2840c5438f3e226e723e50b8da3cb6f5034026ca533c8754fb3e0000000041873a3f591f8e3f39f2323fdd13f43ef639f53e98f2e53f2bf24f3e3776af3f9ddba13e944cdb3e4c740b3fde93773e3c4af03d364fa93f3d52703dab40393f7601963e7441703ee654653fced4343fa787ac3f4ee4103f3db31a3ea803eb3e3983e93e000000003fc11a3e4e3db43f1df001402aca903cbf11503ec172333c720e2b3f49545c3d12299d3ebb57dc3f0e205c3e7de96f3f4584ce3f8196733cef6a583d4db3993d22567f3f253ade3ee27fa73fbb7a7e3fe5378c3e39ee133fccbd07401e6ec13fb65b0e3efdcb383f51a85940682aae3f64b1843d83a83b3fc0568b3e6c84223f5087863f3cc0323c671ae13c580a813fcaaed53da820f03d4d5b593df0e1be3f3b8bed3f21687d3f9ecfe23f0e15a83e9008a23f2abbf03db708c33e8df9384087c18f3f150f523e88aaae3e1588a83eef438d3ec74c1b3d1063a83e300c09404cecd03f0517cb3e843ba83e41e7f83dece4ee3ec359423eb3b9203fd982853e3fce723c146f813f365e9a3ef96f993fe8a1073e392b8e3f225d433d3c2dff3bde61a93faa56dc3e2cf810400545de3f1110ba3e0822143edeec7c3e65ab963eae98633f8308693cc5eab53d19e6bb3ec7a5cb3e9204953f117a5c3f886b6940d0fafa3e373f3d3f6a390d3ec5c7a53e00000000ce2f8c3ee5a7073f00000000872b783e4161cf3d32174f3c0000000054cd493c78c51b400fa2993d100bd03ce707d63fa1781f3f7c3ee53fe82053407cd9d13ed9a80840ac7a343eaa51113e2a51dd3f36c49c3cf4ed243f0f69093d1e915b3e28151b3e9a82a03c37b9ad3fb389713dc9722b40fa348e3fc337803fe789cb3dc8e6903f07308d3fffdee53df5e9243da795dc3ebdfb1b40955db63c3565133fc7803e3f0722003fdb87103f7994cd3f0668173c15e8cb3fa3b38e3d2aaa2d3e441bd43f099dd33ee53f2f3f1f94b93e0000000090ee613f598f484030ab283e843db83f0000000099e0be3f88d8793f3face13a41e1b83f5b8003406ece473f000000006b70893f5465cf3eb463623f3e849f3e70669e3b3682413f28554b3c5d368e3f7560243e7bdfaf3ec59bdf3ff82bef3dce4e423f0000000005b19f3ce434903eec712f3e40c8d13da9c3243e268ec23f000000002ede793e7ea20a3daefbfd3de6214f3ef9b1cb3fece9513ea77ac23ea9c4903e000000003fb7be3f6123b43e876b663ebdd6f53eef82303e6418a53f56746d3d77aa1a40da86a13fde72e83effd88b3d960bdd3d1d9d5d3e76da953f92c0ff3f8c6c813dc952e23ed130193fdd0ac03eac528f3abbcf393d87dc863ef3391a3f221d673fb800d73d2196973f00000000ef13a83e54a4173ef3fb2c3ffdadb43e00000000000000004cc0d33dc1539e3b5ba6c03fbbd9113daf0e413fcc62283d0ccb983d65da463e3fbd0b3f22c5d33e47f8773ea57e103ee1f03f3d2b12883b234c5c3e4889933f03a3e23da3f7993fc533663eb98ddd3f54a8b83ebcf5193a050fbf3f72fbba3ece4f313f516e863f510fca3e9abeaa3ffbe7fa3d3074843f0a758e3de8841d3ffb77b13e1fd14a3f8ce8ff3e2aa3c63b000000001610a93e0ab8ff3e9687b13e1c2b1c40637fdb3d91c6a83e16c98e3f6ce4213f628c383f4162fc3e7c44b03e8387803e40b5883c12622040229b0f3daf1c8f3fc044953ed1f0673e6197f33e3f09823f5809023eceea743fa310063ef20fa03cbeb4833cf394893fccc94e4065d7833e70a9913f28528e3d2e28a43e1053363f2136c43d1b34813daaae713f886add3ed587383f3260a93f2216503f000000004bac993e`, +}, { + name: 'Gold phone cover', + price: 78, + image: `262044403437ba3bac28ae3f51461e3f62a8223eff4db63edd1880404835053f0afd464091b6163fcafbc43f4e0c7f3f1695053f2ce8e93e68cc293fd0b6be3f51953d3cc338264054a5c63d779e163ebb82383f1418993e9ab8f23f5421b63f8187f13faee4aa3fe3ac373f0c919e3ee5c9883ee5b7083ef0ef15404c5d1b3f7f88073ce7c1064063e05e3fdd4b603d88d3ca3ea772a23fd6068240dbc6b53d678fba3e56516a3c1bd7d03faef2213fa5b14940e2f9dd3fff44023fa1a4a23d58cf463ff902953e00000000e5f50c3f45439f3f000000001076b03f799a003fd4cefa3e7bbef33e5dbb1840c026f03f70a1113faa22ed3c703b563dbc67653f28d4703f3c67f43de1426e3da23a0c3e81ddb23ea8c5873ceee9be3e45e86b4041fc943eee20e13dcad90c40fd711e3fcaeec23e3822153dc97dbd3ffbb3b93dd428e83fde0a35401268ac3fb480c23d94e6b83da2cc4c3fe8dd8f3f6618c53f5b7c723f38f3d23dee29883f1274aa3ff400c93e8acf093e0e9dbd3fd01b133e5b7063408cf5423fec34323e8071453ec9525d3e229baf3fa667423ed877033f33adaa3f73bed43fbf47c43dda57a53fc12e7b3ed0faa93f7206ba3e00d8e33d8f819c3ee17bb83f58b68a3e5e4e4b3e257fb13d54d1a33ef8cc223e2cbdf93e3bab5240dd229d3fc9992f3d01dadd3ec722033a1abda93d9d96cc3e0e902d3f52a9f33e6317aa3e63b1223f5733143f352c1b3fa52f263f805d083dddf511403da10f40f6c3c83ed079463f4ebb253f1074603fef26bb3ecc305f3e99f85940eb01c83fb890983ee616433f775a693f05c5fd3e92362f3f62adcb3e47020a40bc04493cf5dd813f6341ee3d5df2a03e0000000040f4183eec8211403603843f7077e33fcd899e3e0553a03fccb159405b96493f5456903e0000000074be4f3f1646313e1344263fde99443e8007aa3eb4f69b3db728423e6fd9963f05809b3ee68fc43f66fdb43e0a6ec13f5f79f33fe8151d3f59e7293f76d6e93d852e22405247d73e78943c3ee6de3c3d55a13a3f6a90933f0ab03f3e5e34713ee644ce3dd9a4ed3f4653213db4a2233fe3f9014005f7a73fa2821b3ff262903fa872383d4c964d3ec2721d3faf01af3e827e933e9bdf533cf36dae3f23b89840c457793f032eca3fbc19b13ef0bb6c3da856003f000000003489d73bbbde4e3f74a48040d65ec23d25182b3f0a851e3e2304803f5b00ba3cb60b3f3fa75c0a40f079f53e8579493f1a5e2440f954a13c00000000ad71143da38f763f4d0c2d3f1f7fb53f80ffe33f8d79683bffa0153fafe7353f98e7124012c7b03fb70a553fdb4c45402fe9733e95214a3f33d3134018d28e3d5b57093f2f9ce63fea7edf3ee343d03fee141e406c6a863dfb5b033e5f50213d36c8564009d3533fca99353ec53d633f3f07183f0d6b424006e9803dbb9ac73ceab17e4055fc863f1e97d13dc460ec3e3617233f91a5b63e052af43c16b08c3e02a8143ffa9d8f401338803d04ad833e41da0e3bf8489b3f493a4c3ff2dfe13f877242404e05033d09e732402fb00d408162a13fa5c9453ec1e72e3ff0358c3d3f78d13fcc67b13f1aadc43e10c7814040f1c53fbbd2303f54c78a3d1dea963edf1e9a3f0990c23e88ac593ea3e8e43e7fdcc33fc812b83eac02b03fac67c53f8d4db440a560993f90308f3e4c20483d5ac1023eb963f73abf18463f14734e3f1c228f3c60319c3e410df23e8ce1c63f000000007c9bc43d840e444000000000bf42823e3dfb123f18a0083fca75ce3f5e6ad23f1b41403f631b224083a3f63e288b0d3f9f222d3f00000000965c0140d50eb13defd0903f1e36123d9fc6c63e0736e53faf4a1a3e5b2d3e40366e903df00ca63d04d3423da0240340492fd63f8051023f2273663fa79e4c3d67613e40b079033d72cac93e98910540e72f2e405933ba3b8d26563f2dd19e3fb090b53f3780a83db3c4d73eb7ed4f408ccd0740ac5f583f72e8ce3e369bc93dc05bc33eff658140a05f083feade1e3fd662fe3bfbd1ae3f3d3da43f2114653d0498f63f43a3bf400723433fb6768c3e5286623fab24853f8503e73f612fd43e04f8623f703a803e7cfa853fe9bc813f9146a93d5e74ac3ec356af3f5c7d903b6e3f8c3f000000009a9bfa3ef848ae3e194f4a3f122e3c3e5b39213facc8573f2210523f363c7b3e6e29783e21cb193da636d73f1a5c0a40bb1cdb3ed230973fe136e63eea12b13d7267493fff47833ff40fdb3dc7e5633f11e0683fd656ca3f04c18d3efc6fcf3ff0ec473f2faf3f3f10060b3e4109f33ee2835b3c34538d3fa86d5740b6504a3c1907b93fb22e3a3e79accb3e5fedbf3e7fa8903d7909303e4463ad3e7f09643f4edd7c3f7913393fe822163f7f3c034039b3373fa7949a3f07a7bd3f347b7d3e49c54b3e7824d23f8710b13d44bd14400ad4f63f88ae393e7388f33d07a64e3e3b400d3f46c1023f9634b03f9f32033c0800253f28fe833ea1e9c63ddb37453f3396533f08d3a43c2c72543f9be3ec3ffcd7a340f4c2cd3ffc4b3b3de32b133fa1c10e3fdae2f33e68cbd93f0c640540ec071940a8659b3d5bd1793fabcadd3ece562a4087010f3e5dcb913f15c27f3e38ddc63def334d3f7901843f1402743e1422ff3f184b6a4045c4703f3735eb3e4758503f093c033f45e5223d4952d73e9939253f146dc13d9fdf293f94891c404efa843f346e623f49b9a23f44536f3f34d46c3e5e28783f00000000f92b8d3e6a09403f1984163e83f7a73ef833ae3fc8f52e404e42993fc761753fac9fa93ec9c4a53e5517bc3f1447463bc48a263ed979613f4726f73e36b6bb3c0d9c3c3d6c5b953f6b222b3cf46afe3e`, +}, { + name: 'Patio Light', + price: 120, + image: `35d4113f32cdd43dc803043e85ff453da392643fa1b3da3e12cc113e5b99db3e7401653fe23d213f2be8953f54c82d4080137e3d23bc953e2392843e2317104000000000ab58703f44826040aed8a53fce99c33f9146a03e2284283f0a659c3edd996a3ef619ed3f5edac53e0923853ed974403f3b13fe3f5b81b03e01ac1c3e6e0de63ec81f723f2a408c3ec8398b3f98455d406e52333fb43cb03f0d6fb53de6910c3f9a54843f92ad0e3dc788bf3f720c673f778b643f2354cc3f265b0d3f3337983edea2413e537a1040486a6b3f2e567b3f1668db3fbc6152409df0cd3f314d9c3db2f9893fc5c3053f72cca23f4760d13e04faa83f95f9543eab420840548f0b3f0923143ec5a6b73ff85aa33eb201aa3e5617fc3eaa557f3f190d3c401b77fb3f8735443f03a3853d9503f33f2284be3e10c8253f3847503faae4753f33109e3f15c6df3ff6b4d63de8310d3f059932405487293fe86c923bda5a373e479c3d3eea87cf3fd8367b3ff6c76e3f660de43cd0d69a3eed00163f9d0e0e400a175c3f9fd8a53d00000000e8be963ef83a673fda9a933fe1651540b9a34e3efc29df3dcada8d40a85cac3e14150a3fc800af3e39019b3f4d048d3fa3dc6d3ff0730f40c95bbc3eeaf9ce3f20b1203d801fe03cd1fbc93facb54a3fcd915a3f4457a13eac1cae3f132b193fe58b5a3ec7a57f3fd6ce9f3e18988c3f485ae83ebd88f23e37832f3ff981c83ee23f2240db66a03f5ee4343efeac033fe7021a3fbe47a13e7265f13ef0d47a3f10541d3f5fbfca3db286dd3e7a30983e37e4f63e409dbc3f52c5233e4159323f61a2254068f6183fe179483e5a38453f459a2b4095c0a83f2574b93ecd5fb63d1c00a43ee86f513f7046f03ff34eb63fa35ea03e814cb03fbc4aa93fdc7d1b3f6528993f72d1673ff7b8c23fdb0e8e3e58643c3f3fff293f59ab413ed65a013fc4eab53f7b75373f6a2d453f2637283f03d8563f28bdad3c38a1b33e112c313f90e2243f0156ac3fccd5803f34faf73d7bd4803e3b04cc3c7779a73ee6e1c93feed9323fc1128b3d12151f400de8b53d6f09cc3d0d02373fc850f43e79c7a83dc573263fe35c5d3fc9bfd53bb26aa63f96d1a43ddb6d163e2c7eca3fe6ad363f9963283f0d09983f7423063dc522333f8a02573f851d2a3f39f9fe3d0169143d4cc59a3e16f0fa3fa1ad213fb937153f23ded03dc4e91f4078c7893f000000007d0f223fc54f933ee108c13e9bace83fcba50f409223d33e8b8e993fb336db3edd442e3f2555c13ed40cd93ea618043e901ce03f0573da3d5573293f388e023ef6c6a33c63db193edabb334036be2b3fe24c893f22bdac3fff31bd3e087bb63f647c9f3ef4e95d3f30dead3ff9747d3ec386263fcf2c0e3f74d9ec3e6cfb9b3f09c2b23e80e3a13f1988733e15b7ca3e689b1e3f4716933f840ae03ea1a52540ca2b533f227c883e63c1073e2558ca3e70e9a83e1668b13f133e213fbb9fbd3f0d08723ff9f1553f2f09f03eac3cbc3e8d1b9c3f07e81e40c85e213ddd4109403fbe863eda0f3a3e0462cc3f3768ad3e140ebe3e5b3ab73e94cd1340ea89be3fe647483d7c150540830b173fd4bf1b404379093fb73fee3d6c37133f1d80ca3e9a99653fc979aa3f8ffb123f2a52143fb971373f9807923ff6ea3e3f5a05e73eaca1793e21db3440f7c0e13e784c514059cf943e33d3553f0fb2893cc4c655405f0e3c3f40b11340dea3233f52301b3f76c8ef3f9d1aa93e9ac4553e807b793ea599573fd9872e3f805b6440e69cf23d95d1ba3e22150d3ff4c3fd3e165f3740213e803d4813bd3f2c33df3edb8b8e3ef6de2d40af40d33f7949813ef011613bdae2e13f454d8b3e684c763fd22a953fb699963e322f583fd98b1a3f2f39283f03f1733f4d51f33f3c253d407601643e14282a3f3fb42e3e4d03263f24d0963ff962154001f0823d38d7f73f03dba73ed430893d3f8e263fe5319e3ee5c5de3f99d39d3d4e42404061ae2240918eb43fd6b7443c0cd1a53f77a7c240d6ad223f990db73f7dde3f408764ce3f3facc23f837dbb3e3aa39a3ea1b9de3c10505a3f7b7e443f03187a3f7c23b63f3952523ff8121d4062f7733fa331fb3f6825ee3c32bf0a404441b63f4d9c4f3d12ec7d3faffa853fbc940a3dae88823ff98b1c3f1b3e5a3f5158353e619bbf3db74e433fb9a81e3e096e5c3d2c7c7a3f5be0843eac75d13de194d23fe368a53eecd1903f417ceb3faf9fa13fca7dfb3f1157313fbb18d43e5d33ea3fd001af3eeec31f3e5f12333fd54b3b40129f993fabe81b4087fba83e11319e3fecc5013feaa4b23e79010e40a26dc33d4120b63f4409bb3f43a5473f9d0f533fc501913f3218673fda34833d7637fc3d1a70dc3fd6a8d93cfc859d3d18c7503f0c07a63fa2cf1f3fa7d2ae3f557a4d3e199ee93f944b723e8a30483c25ae3f4034b98e3ebc10263f5a5914401da23740f77cc73ef21a703f9f297a3ff63f8e3f25e7044021846f3f65a61c3f4c953b409ff8593fe56bb33e703bd03d2a84283e9a22c540cef5733d66873e409c4d963f896b373f4ab0a43e15555a3ec4053a3e3737f23eca13893fe17cb53f38d4943ffcaad23e0d4bb43f7492113f2ea7233fe56fe23efccec23f2245733e18c5c63ff678373e1422983f01e3ce3fea06323fd9258b3e3932cb3eaa2bcb3f5fd6073e90af3b3f2892f83ebd710a3eb4561440c1133c4021d3234007da1c3f7f2d1f3f39150640bf045c3fe337543c5d0b863f0a3e903fa5faee3fa27f6c3c6a3e673fa8891f3d7cb28c3fe132b13fb9d5d43fdea3b43fd9d7383edd9cdd3e85530f3c5a43dd3e2b151c3f6533b63ef8929b3fc2311f3ea534803e656dc93f`, +}, { + name: '2-seater sofa', + price: 400, + image: `a8cd873f83e1553fe701173f3fabc83c9fd6613f51aa343fb43b883ff173083f207d943ffa6e19401618a93ff600ff3fc410763f493d443f5d579a3f1f0ddc3f4e0bfd3d25fc2b3faf43453ed146783fb498713e486bcb3f8a7c6d3fe7e9aa3f59482b3f1c34013f03fdee3e9e412940035a313fa5967d3e7983043f1f93393f5220233f85d9ea3dd6eacc3db48e243ff22f414038947d3e3c784f3f381ac33ff128a03e51cfcb3f81716b3f3fddd83f3d5b063f3bf4f63d50a1a13ebb111040f7a3573e12d1963e78a2ba3f8d05053fe474103d3f03d53ec12b2a402ae43b3fb0ea613facf0573f032c0f3f2e22b83fdefebd3f631b6e3fddfc823e2816d43d0a2dab3f5e7e653f3f67423fda7bcd3e7f3cde3e75530f3f094e233e225bb43ee528113fc4de713ec0ab4b3ea6baad3fd3c19f3f68f4473d49b8c83e416bdd3e2c94673e948f893f7b8c4d3ebf903e4003837e3ea7eb633facd6fd3cb4930d3f32d705406237a63fc97c2c3e7ae4143e98b9ba3e5b4e2b3ea6e24d3f67d8053fc4f049401a59623fb426be3f9fcbff3e5904153f707dc63f811bbe3e21c9833fda22163f9fa9f03ef39a3d3d8c381c3e2e3d2e3f41453c40ae0f1e3f0b721f3f8afe9c3ddb492d3e1b72403fa6baa13f2a517340482af53e10213e3fdbfb7d3f014e473e283b2840a4289a3fcc29e83f1b6af73f484b043e8420de3fd4b5853ec48a9d3f3784aa3ee14a833d1556eb3f6d5b933f5f64ce3f908ebd3e1452493fc161cc3e0ad08e3e122aae3d15676640394cbe3fefc3d43e905dde3faf9c433e8622a23c9d04683ea009104052cbda3f24689d3e5ee3b43fb2b92e40000000004c87e13fc3f3ae3ec4f2af3e4720083f25763d3fa767323f8a506f3ee395c43f5e9107402819973e8a49033f806a9b408e8c883fe15a943f372dcc3e22ff1b3fde3bae3f21c9a33f2259803e07d15c3d8576fa3f4d45d63e6fdc3c408d41b43f7824fa3daefb853e1a6dae3d167ce73eb7b20b4054a0963e7db4c73e74f1484004fe7b3f29e31f3f0433183fa9191b3f7280573f91746b3d3d17263f1bfea23d833b1b40099baf3e22d58a40086bff3d794df73e56d56e40bd531c4034cc8b3f5801a83ed4efed3f18ec3d3f770e043d7b82823e12e90d3fa55f033f967fb13f14cdac3ff35e6c3eb30cd43d5272373ede6bdd3e283cd63e7663573f907ad83e21c31f40de97803faaed643f1266a93f5451153f375b433e9a86ad3f4eb6d63fb8aa233f75a21040a776723f83d4f23d5aaed93ee6405d3e49b2063fb465853f7e5a143fccc19d39a2e8283f700b023f58e1d03ee1a01b3e7d62ac3bbf1adb3c25f87b3ff9d2283e30daa73f7953203f23b8533f3cc0833fa593403f339ab03c143e733f9d28f03e19e5d23ff342a23ee1e1683e437e4f3e8cb9bf3e16cc2a3f40d7033fccb4bb3e22258b3fec446a3e9d0ba63f7f94e73efb7fd83f651bb13e894c883f18b45c3f9f0bfe3e11b0ea3e52bd813fb88d9d3d0574043fdb05ef3e3931eb3ed82f4c3e7c688f3b28be013f988eb53e5db9e03ff755423feede163f8af6253f2adb21401259b63f3082963d2c7aa63fc7cfa83ef2cdf63d6c88133fb6541f3fbbf2c73ff0a2ec3fac75b13eb92810407cd5a53efda7003eb9604e3ee31fa93f32da173fdbd0383e402d2d3f964f2a3f68b0c13e45c81a3f94f4f03fc1ada33ea363bb3d4459e03ced6a023eb724f33e66a7093faa88cb3e64e2153f88feb83ff31d003e4708933fca7bf63fdf02c23eae2fb03ec7db133f4ec5153f50f5b13f5f25423f157f8c3ef9e8fd3e3991353fa1eb243ed4703140ef72af3e2a2ba43c386b143e8cd4843ea74b443e6895f13c7f2d0b40da5731405b33653f0358e93f799ba83e89b4ef3ed96ac23fe352463f6b9d823fb685aa3e3cd3e13cb2fd1540cde8fc3ebb39103f5e3ac03e0e6dcd3f78be373f7759bf3f33e6833f94309f3f50b4653f00000000f77f0840d619cb3ff0b3353fff7dec3e50e2483f95693b3f47b43d3ff7183b3f2846e03f6b0e4b40bdd7423f81eea53fb498853e10b02240b914253f3495443d10e8323f7433483ec569773fbf90f83fb450063e2c89373ecaa807406569fa3e1d708f3fade6143e2b07943fa77e9340108d2540a57d7a3e7854093f0729643f55e22d3f77020f3e946ed33ff9f025402118413ea7541f3f3792a63dbdf4933e7cd6363eca9e773faed1813f0715753e016df83de1730b3f7084113e66893c3fff723e40571882405306903f7b988f3fde962a3fb7a4a33ee17ce23fe1a02e3f8cf18c3fa3d9ea3f3d7ccb3facb2873f8d0e793fc7e02c3f1f4de63f9c2b1b3f30345c3f8e42823d49aab43d9b56e63f61add23f9072b93d7013dd3d47994a3fdd49b33ef83ea03ec813c23f2ab0233e3707e93f142e4e3efbf68640ef4bb23f053fd23f41829c3eb8404a3f5d41833e43d6a73e6e74063ba86f813d3fe3d43d1eb2af3f8841c23f1fa06f3e3f11e04022512b3f34ccb13e9ee8b23d7994c03fbcf8ba3f925fea3fd43ca53f3c66ca3e0e2bad3ca22fee3f70ba733f4ad3713e19ff6f3d4ca77a3ce2b3623fd18ef13e7718d93ee0be9e3f78211f3fac1c1640147741401f697c3ef5ff193f4c20283f01ea9d3f74903c40d9decf3f67420a3e4a1e7f3f4402aa3ee3f8413d9e3ec73f5a22d83f55700a3f48cabb3e99feff3e580d813f5581eb3f59f5803fca4cad3fd6ba1b3f051fdb3e2284a53f4a9f174077eed03e3205163f0bb4243f70d1c43fc7e72b3f66590e40d5c2873f22f1283f8d6e713fc359c93e58c0943f8a66b13db2bfce3e5d28303dc8f7543f3fb0c73c2ddd8c3f94db23405042443f6241a33f37407d3d`, +}, { + name: 'Comfy Chair', + price: 200, + image: `5101003f8b25923f1db69e3f1465113fdec3993b1000813f321fb33cc1d53f3ff9e68e3f2ec10840c869023f4082b03fe1711b3fd0fcff3debc3753e7086be3f1f2f8d3ec3acbf3f5059433fc8e2e43eae18093e6a935c3fafd41f3f3b48fa3d2e2a8a3f00000000688ef93e88a4083fe8439b3e33428a3f2b2ce13eb09d263f8c44113eb0fed83e907fd43eb90bca3d38c21c3fe1b4c23e87426e409de2a23da3030b3f0f0e8f3fb919283e414c883f98c7ca3e4cbcdf3fe767a03e4148683d433802400059173e6cb4c03f362f1240db64b53e9560613fa155c03fd5a7bd3f6a7db83e167a843f9bb5433ebfdcd33f3c72383f8dff673e785d9a3e6bf5223ef08e8e3fc4fc153fba7a8d3f4cf9bd3e32ab593e3b8f1e3e03e3813fb896a73f3f7e473f157b463e59306a3fe8ff973cc794b33f3fa74c3e14af573e1f9a85402631143e83fb8b3f88a8b73af8f9013f4df51540a799eb3e45fa1a3ef6d9223f67ab8b3f3faa6a3e951fbe3fbf33903fea9a853e3d10123e66435e3e5599c43f44b90a404869bb3e5f908f3e511bbf3ed111713dc77bc03d17ac0e3fd63b8f3f95c1353d826f83409d0e103f8965033f9e9d313f9e0ecf3f65760a3ed57a703db26e0d3e08f8bd3d6ea78d3f21428f3e65a7803f12c2df3f7b97083d6e8abb3f70af883f197a753d7b3e4e3e8096023ef760803fbde3283ccad13e409eb84f3e3ff1503e5bc0833fea91bd3e7377d93f039fe23f764e2e3d4eb4e73e65c1b03e32989b3f0a1f133d4a63833f2c8ea43fcc8a253fd84e6c3e0c59883e98b1713d3435653e22673a3e4d00eb3c7dff163fc0a1b03ed98f493f1a251f3f08d9783f83b6dc3fdf001a3f6149983e8083f33eb816643f1569023ff33dc63d5ebcb73e874a6b3e50d2873e28798f3e89764a409138da3b6a9ad63fa7f8503e14f51c3d49ca793e44015c3fbf65603eb9b2f93ec8bb8a3e1822ee3de17bfe3fd93a243fdeba0e3ef2f7553e657d8a3fa86ca53e9e64613e22a20c3e5e55af3e2eb2b03f928c323fccfec63ee880423dd2b9e63d7d602e3e2a288b3e2525a93d9abf483d0ccfaa3e7f0ff23daa57c340cef7d03d256abe3e44d32d3f1fc9703fe3874a3f847eb23f386bb73ff0dd3b3fd474bf3f085ced3d2a10b23ea25dd13f98b39e3fada5803f3257853f8f830d3fe81f9e3ebf50c33e72e6c43fe154c23fdb64ec3fb820463da1fc403e39809d3e482ed63f4d3fc83dc7cf9c3f59f4c63eb56ba23e9ab9f63ef423ba3f674a793f3f055d3d1d7c063ec4b7303ff32c5f3f0a18ca3ef87d5a3e513a1e3fec22f73c2f11263f6eefb13ed98a7e3f386e243e8cdd12406135023f32dd7e3ff9dd963d2a77393d839d6a40eabf193cda02ad3e0838433f65beab3fa68b043ed03d653f16ac483d9b43c33daf02f23ba565863e66568a3f8f3da23c4ed8ee3f5ed0223f7682693f7cece53edb2e6b3fc4ad293e829c183f2146003e6c600c40a684bf3f49e96e3dc126313fe24ec53ededa783f7823a13de7bbe83e9d39583f9f3f333e04c7613f61d4343f61a3463d66cf583f6cf0b13ee1ac463fe5d7843fb9fc353de59aeb3e509cc23e11bf7c3d447f103f9ffde43fe1dc3a3eb34a183f301e3c3f7feb453c9242683ec4c12b3e82e3133f557e6f3c2f2c443f8a1b01409042893f943d853f4e114d402ab7a23f5d09483f1d3f0f4083ef623ed61f433ea544d43e0e92fe3e38f0283fea7d033fb8288a3e0dcddf3fb78cde3e28ab2f3f84854340548b473fc758013b78449a3ef5b6803f9b65ce3f96d5603fd2928e3fe15424407479e53dff78c13f395f0440f025b73ef9b2a33e6ba2373fa51f5a3f30f1143f895eaf3efbdb283f22ae333e95d2e73f45dce33db2070a4091e91d3ef8d98e3dd9cfd03fb46e7c3e2fe8433ed15dc53e7092893fea6e853f48a48a3f2646ea3f63e98a3eb31c2d3eb722593eedc1883ed26b8e3e114d6a3dac019e3f4e9f943f1567b23f6f6a254079d3243fa5ee5b3e70fc0e3f5b894740162a873f0e14d73f625f0e3fecf84f40fc360d3f22adf73daa6cad3e30212c3f01a68a3ddae0393f3248703de8afad3dabd0e23f7949083ec86c7d3ffd2dbf3f091eb73e5f6d9c3da6b7223e6b3edb3e150c9d3e81363e3fb420be3f9de9ba3bf3dcdd3e8f99113eb9cafe3d2ceb3b3fa558ac3f7356063eb236f93e1d4cdf3ecc5db53ec4b2423ea2b5823fdb19413e4a57603f8bac1c407d57c53fe2e25b3f84399e3fbcf9973fdd93153f498da93f3c53623ffb929e3eb7a6343fd4f8f63f768dd13f885d153fcdd11440befe8a3e6ee900406d75013f95e97f3f54b4303fb37a953fda9ce23de70c3c3f747eb13e6efe913de2cf613e68a5633e19cb633f1a228f3e0c71b23eb5718e3e9d06ec3faf5c2f3e5907103f592ccb402128463fc8e2e93e6ed22e3ff61d243fef81f43f9535b03f84a22c3f86689d3fc3050a3f7d209a3e28ae033f8c62883f486c283f39a6d93d44d28a40d4cecd3d019c363fefbeaf3f7e30923eb28d033d30db343e77a3f83ed185023f18fe7f407690d53ed066213d58ad983efda3723f2b6ab83d6adee33ddea5ed3d3f87813f40cc033f48cb953fffba163eac9bca3d74c7923f262fdd3ee5080a3fc40efb3e99692d3f80573c3d9622933fa2b8aa3e186afa3f5dfda63f6b9201402212e73f6fa8033ffb78123fd70da43f07899d3cc171b13fd1f8f83a68ddf33f4d84e43db9ac8b3f1b6b1940d171503f224e153e6a9c773e31650b3f5baa283f30c2bd3b00000000623ad03f70482b3da918923f7c6cc23de80dd93fc586f33e956e743f26a0a93e61c4b03e2a787e3cd9c7bd3efbe1d73fdb3ca13e5a601f3f1fc9623e`, +}] diff --git a/spec/functional/search/vector-hash.spec.ts b/spec/functional/search/vector-hash.spec.ts new file mode 100644 index 00000000..dc742fd6 --- /dev/null +++ b/spec/functional/search/vector-hash.spec.ts @@ -0,0 +1,98 @@ +import { createClient } from 'redis'; + +import { products } from './products'; +import { Client } from '$lib/client'; +import { Schema } from '$lib/schema/schema'; +import { Entity } from '$lib/entity/entity'; +import { Repository } from '$lib/repository'; +import { removeAll } from '../helpers/redis-helper'; + +describe("Vector HASH", () => { + let redis: ReturnType + let client: Client + let repository: Repository + let entityIDs: string[] + + // define the interface, just for TypeScript + interface Product { + name: string; + price: number; + image: Buffer; + } + + // define the entity class and add any business logic to it + class Product extends Entity { + } + + beforeAll(async () => { + // establish an existing connection to Redis + redis = createClient(); + redis.on('error', (err) => console.log('Redis Client Error', err)); + await redis.connect(); + + // get a client use an existing Redis connection + client = await new Client().use(redis); + + await removeAll(client, 'ProductHASH:') + + entityIDs = [] + }) + + afterAll(async () => { + await removeAll(client, 'ProductHASH:') + + await repository.dropIndex(); + + // close the client + await client.close() + }) + + it("demo", async () => { + let schema = new Schema( + Product, { + name: { type: 'text' }, + price: { type: 'number' }, + image: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', initial_cap: 5, block_size: 5 } }, + }, { + prefix: 'ProductHASH', + dataStructure: 'HASH', + }); + + repository = client.fetchRepository(schema); + + await repository.createIndex(); + + async function loadProduct(product: { name: string, price: number, image: string }) { + let entity = await repository.createEntity(); + entity.name = product.name + entity.price = product.price + entity.image = Buffer.from(product.image, 'hex') + return await repository.save(entity); + } + + for (const product of products) { + const entityID = await loadProduct(product) + entityIDs.push(entityID) + } + + // TODO: figure out rawSearch / where query encoding is happening ... + + // execute a raw search for the first product image ... + const results = await redis.sendCommand([ + 'FT.SEARCH', 'ProductHASH:index', '*=>[KNN 2 @image $query_vector]', 'PARAMS', '2', + 'query_vector', Buffer.from(products[0].image, 'hex'), + 'RETURN', '3', '__image_score", "name", "price', + 'SORTBY', '__image_score', + 'DIALECT', '2' + ]) as any[] + + // ... and we should get the first 2 products back in order + expect(results).toBeDefined() + expect(results).toBeInstanceOf(Array) + expect(results.length).toBe(5) + expect(results[1]).toBe('ProductHASH:' + entityIDs[0]) + expect(parseFloat(results[2][1])).toBeLessThan(1e-4) + expect(results[3]).toBe('ProductHASH:' + entityIDs[1]) + expect(parseFloat(results[4][1])).toBeGreaterThan(0.2) + }); +}); diff --git a/spec/functional/search/vector-json.spec.ts b/spec/functional/search/vector-json.spec.ts new file mode 100644 index 00000000..3f59f44f --- /dev/null +++ b/spec/functional/search/vector-json.spec.ts @@ -0,0 +1,98 @@ +import { createClient } from 'redis'; + +import { products } from './products'; +import { Client } from '$lib/client'; +import { Schema } from '$lib/schema/schema'; +import { Entity } from '$lib/entity/entity'; +import { Repository } from '$lib/repository'; +import { removeAll } from '../helpers/redis-helper'; + +describe("Vector JSON", () => { + let redis: ReturnType + let client: Client + let repository: Repository + let entityIDs: string[] + + // define the interface, just for TypeScript + interface Product { + name: string; + price: number; + image: Buffer; + } + + // define the entity class and add any business logic to it + class Product extends Entity { + } + + beforeAll(async () => { + // establish an existing connection to Redis + redis = createClient(); + redis.on('error', (err) => console.log('Redis Client Error', err)); + await redis.connect(); + + // get a client use an existing Redis connection + client = await new Client().use(redis); + + await removeAll(client, 'ProductJSON:') + + entityIDs = [] + }) + + afterAll(async () => { + await removeAll(client, 'ProductJSON:') + + await repository.dropIndex(); + + // close the client + await client.close() + }) + + it("demo", async () => { + let schema = new Schema( + Product, { + name: { type: 'text' }, + price: { type: 'number' }, + image: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', initial_cap: 5, block_size: 5 } }, + }, { + prefix: 'ProductJSON', + dataStructure: 'JSON', + }); + + repository = client.fetchRepository(schema); + + await repository.createIndex(); + + async function loadProduct(product: { name: string, price: number, image: string }) { + let entity = await repository.createEntity(); + entity.name = product.name + entity.price = product.price + entity.image = Buffer.from(product.image, 'hex') + return await repository.save(entity); + } + + for (const product of products) { + const entityID = await loadProduct(product) + entityIDs.push(entityID) + } + + // TODO: figure out rawSearch / where query encoding is happening ... + + // execute a raw search for the first product image ... + const results = await redis.sendCommand([ + 'FT.SEARCH', 'ProductJSON:index', '*=>[KNN 2 @image $query_vector]', 'PARAMS', '2', + 'query_vector', Buffer.from(products[0].image, 'hex'), + 'RETURN', '3', '__image_score", "name", "price', + 'SORTBY', '__image_score', + 'DIALECT', '2' + ]) as any[] + + // ... and we should get the first 2 products back in order + expect(results).toBeDefined() + expect(results).toBeInstanceOf(Array) + expect(results.length).toBe(5) + expect(results[1]).toBe('ProductJSON:' + entityIDs[0]) + expect(parseFloat(results[2][1])).toBeLessThan(1e-4) + expect(results[3]).toBe('ProductJSON:' + entityIDs[1]) + expect(parseFloat(results[4][1])).toBeGreaterThan(0.2) + }); +}); diff --git a/spec/functional/vector.spec.ts b/spec/functional/vector.spec.ts deleted file mode 100644 index 71f76c51..00000000 --- a/spec/functional/vector.spec.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { createClient } from 'redis'; - -import { Client } from '$lib/client'; -import { Schema } from '$lib/schema/schema'; -import { Entity } from '$lib/entity/entity'; -import { Repository } from '$lib/repository'; -import { removeAll } from './helpers/redis-helper'; - -describe("Vector", () => { - let redis: ReturnType - let client: Client - let repository: Repository - let entityIDs: string[] - - // define the interface, just for TypeScript - interface Product { - name: string; - price: number; - image: Buffer; - } - - // define the entity class and add any business logic to it - class Product extends Entity { - } - - beforeAll(async () => { - // establish an existing connection to Redis - redis = createClient(); - redis.on('error', (err) => console.log('Redis Client Error', err)); - await redis.connect(); - - // get a client use an existing Redis connection - client = await new Client().use(redis); - - await removeAll(client, 'Product:') - - entityIDs = [] - }) - - afterAll(async () => { - await removeAll(client, 'Product:') - - await repository.dropIndex(); - - // close the client - await client.close() - }) - - it("demo", async () => { - let schema = new Schema( - Product, { - name: { type: 'text' }, - price: { type: 'number' }, - image: { type: 'binary', vector: { algorithm: 'FLAT', dim: 512, distance_metric: 'COSINE', initial_cap: 5, block_size: 5 }} - }, { - dataStructure: 'HASH', - }); - - repository = client.fetchRepository(schema); - - await repository.createIndex(); - - async function loadProduct(product: { name: string, price: number, image: string }) { - let entity = await repository.createEntity(); - entity.name = product.name - entity.price = product.price - entity.image = Buffer.from(product.image, 'hex') - return await repository.save(entity); - } - - for (const product of products) { - const entityID = await loadProduct(product) - entityIDs.push(entityID) - } - - // TODO: figure out rawSearch / where query encoding is happening ... - - // execute a raw search for the first product image ... - const results = await redis.sendCommand([ - 'FT.SEARCH', 'Product:index', '*=>[KNN 2 @image $query_vector]', 'PARAMS', '2', - 'query_vector', Buffer.from(products[0].image, 'hex'), - 'RETURN', '3', '__image_score", "name", "price', - 'SORTBY', '__image_score', - 'DIALECT', '2' - ]) as any[] - - // ... and we should get the first 2 products back in order - expect(results).toBeDefined() - expect(results).toBeInstanceOf(Array) - expect(results.length).toBe(5) - expect(results[1]).toBe('Product:' + entityIDs[0]) - expect(parseFloat(results[2][1])).toBeLessThan(1e-4) - expect(results[3]).toBe('Product:' + entityIDs[1]) - expect(parseFloat(results[4][1])).toBeGreaterThan(0.2) - }); -}); - -// Vector values taken from RedisInsight example (hex format to make comparing bytes with CLI slightly easier) -const products = [{ - name: 'Mobile phone cover', - price: 50, - image: `55cb1d40f7d0853e18b63d3d120c913fd182893e323a703eac4efb3e8891213e520a03405d2a423d44fcc03e6bed1d3f48eaa43b0a5d863fd153bc3f4d8a023f000000004189713f41ef543ea1f74a3c434fc63ed24b5c3e92559c3db4066b3f6ff9c63e4920883c565b443efb7c063f000000001288fc3ee264d23f000000007303de3af93a1a3fc10fc73e00000000000000001f52403fc3c7fc3f03a7463f6a61813fe613d73c9132ce3f77ee093f794ac03fca66c73fc0b35d3f00000000cab1d63f4b08853fdb93f33d30b08d3ed9bc943cfdb7203c0803c53fe33f633f00000000a5a9963e524c7c3f2104253fe9db8e3e466a893db8c60a3f4032a33ffd9c583f00000000fb631f3f0e50383d7847223f7f5a5a3d9a5cea3ef0092540c341833ba534833c22a2333f28e6ba3e8a401b3f9b66a23b92336e3f2c8c9d3fcec1e43f744157404ef16a3f8a63393e4c422e3d00000000ffacd53eacf1803ec6de1f3f636aa03af052bd3e11c0bc3f1a24f33d437b043ea244a03e98a78b3dd86008407724a03e3f0a333dd676fb3d79ffd93d747c143f1f1ac83a874df33fe1f69b3f72cd9b409b945e3e3bd9043d6c12a13f186de03dc9ec293c1b83cf3d917a9d3d30b6513df375ec3d884c943d773f733db45ae13c6aee8e3eb7aa333fe8c64c3f6a97143f700d5e3cb63a483e2296393c0000000014703d3f94198f3e18c7153e7d2c4e3e323b413f54123f3d1026223de82f6f3d6a9d2e3fe2078d3f3796d33fadd6973e7b249a3c6f86413eb41e8f3e3d662d3f5123cd3ec1fd343f0498533fc48aff3dc8bf4f3ef64e3540dd13163eaa80143f5f70683ea7dee23faae9d13ec90d903fd62e173fc942db3c3203f23e68d03e3f6557793f6e37893f0330b23dea1f7f3e1f8e343e4ae1ca3eb21a303ffd6adf3e37c6003f0000000099f2213e922acd3e3736cd3e7d776b3f5ab7993d16f5453df6d5133bf4f0a53f6112343ef250d83dff01813f817b2840c5438f3e226e723e50b8da3cb6f5034026ca533c8754fb3e0000000041873a3f591f8e3f39f2323fdd13f43ef639f53e98f2e53f2bf24f3e3776af3f9ddba13e944cdb3e4c740b3fde93773e3c4af03d364fa93f3d52703dab40393f7601963e7441703ee654653fced4343fa787ac3f4ee4103f3db31a3ea803eb3e3983e93e000000003fc11a3e4e3db43f1df001402aca903cbf11503ec172333c720e2b3f49545c3d12299d3ebb57dc3f0e205c3e7de96f3f4584ce3f8196733cef6a583d4db3993d22567f3f253ade3ee27fa73fbb7a7e3fe5378c3e39ee133fccbd07401e6ec13fb65b0e3efdcb383f51a85940682aae3f64b1843d83a83b3fc0568b3e6c84223f5087863f3cc0323c671ae13c580a813fcaaed53da820f03d4d5b593df0e1be3f3b8bed3f21687d3f9ecfe23f0e15a83e9008a23f2abbf03db708c33e8df9384087c18f3f150f523e88aaae3e1588a83eef438d3ec74c1b3d1063a83e300c09404cecd03f0517cb3e843ba83e41e7f83dece4ee3ec359423eb3b9203fd982853e3fce723c146f813f365e9a3ef96f993fe8a1073e392b8e3f225d433d3c2dff3bde61a93faa56dc3e2cf810400545de3f1110ba3e0822143edeec7c3e65ab963eae98633f8308693cc5eab53d19e6bb3ec7a5cb3e9204953f117a5c3f886b6940d0fafa3e373f3d3f6a390d3ec5c7a53e00000000ce2f8c3ee5a7073f00000000872b783e4161cf3d32174f3c0000000054cd493c78c51b400fa2993d100bd03ce707d63fa1781f3f7c3ee53fe82053407cd9d13ed9a80840ac7a343eaa51113e2a51dd3f36c49c3cf4ed243f0f69093d1e915b3e28151b3e9a82a03c37b9ad3fb389713dc9722b40fa348e3fc337803fe789cb3dc8e6903f07308d3fffdee53df5e9243da795dc3ebdfb1b40955db63c3565133fc7803e3f0722003fdb87103f7994cd3f0668173c15e8cb3fa3b38e3d2aaa2d3e441bd43f099dd33ee53f2f3f1f94b93e0000000090ee613f598f484030ab283e843db83f0000000099e0be3f88d8793f3face13a41e1b83f5b8003406ece473f000000006b70893f5465cf3eb463623f3e849f3e70669e3b3682413f28554b3c5d368e3f7560243e7bdfaf3ec59bdf3ff82bef3dce4e423f0000000005b19f3ce434903eec712f3e40c8d13da9c3243e268ec23f000000002ede793e7ea20a3daefbfd3de6214f3ef9b1cb3fece9513ea77ac23ea9c4903e000000003fb7be3f6123b43e876b663ebdd6f53eef82303e6418a53f56746d3d77aa1a40da86a13fde72e83effd88b3d960bdd3d1d9d5d3e76da953f92c0ff3f8c6c813dc952e23ed130193fdd0ac03eac528f3abbcf393d87dc863ef3391a3f221d673fb800d73d2196973f00000000ef13a83e54a4173ef3fb2c3ffdadb43e00000000000000004cc0d33dc1539e3b5ba6c03fbbd9113daf0e413fcc62283d0ccb983d65da463e3fbd0b3f22c5d33e47f8773ea57e103ee1f03f3d2b12883b234c5c3e4889933f03a3e23da3f7993fc533663eb98ddd3f54a8b83ebcf5193a050fbf3f72fbba3ece4f313f516e863f510fca3e9abeaa3ffbe7fa3d3074843f0a758e3de8841d3ffb77b13e1fd14a3f8ce8ff3e2aa3c63b000000001610a93e0ab8ff3e9687b13e1c2b1c40637fdb3d91c6a83e16c98e3f6ce4213f628c383f4162fc3e7c44b03e8387803e40b5883c12622040229b0f3daf1c8f3fc044953ed1f0673e6197f33e3f09823f5809023eceea743fa310063ef20fa03cbeb4833cf394893fccc94e4065d7833e70a9913f28528e3d2e28a43e1053363f2136c43d1b34813daaae713f886add3ed587383f3260a93f2216503f000000004bac993e` }, { - name: 'Gold phone cover', - price: 78, - image: `262044403437ba3bac28ae3f51461e3f62a8223eff4db63edd1880404835053f0afd464091b6163fcafbc43f4e0c7f3f1695053f2ce8e93e68cc293fd0b6be3f51953d3cc338264054a5c63d779e163ebb82383f1418993e9ab8f23f5421b63f8187f13faee4aa3fe3ac373f0c919e3ee5c9883ee5b7083ef0ef15404c5d1b3f7f88073ce7c1064063e05e3fdd4b603d88d3ca3ea772a23fd6068240dbc6b53d678fba3e56516a3c1bd7d03faef2213fa5b14940e2f9dd3fff44023fa1a4a23d58cf463ff902953e00000000e5f50c3f45439f3f000000001076b03f799a003fd4cefa3e7bbef33e5dbb1840c026f03f70a1113faa22ed3c703b563dbc67653f28d4703f3c67f43de1426e3da23a0c3e81ddb23ea8c5873ceee9be3e45e86b4041fc943eee20e13dcad90c40fd711e3fcaeec23e3822153dc97dbd3ffbb3b93dd428e83fde0a35401268ac3fb480c23d94e6b83da2cc4c3fe8dd8f3f6618c53f5b7c723f38f3d23dee29883f1274aa3ff400c93e8acf093e0e9dbd3fd01b133e5b7063408cf5423fec34323e8071453ec9525d3e229baf3fa667423ed877033f33adaa3f73bed43fbf47c43dda57a53fc12e7b3ed0faa93f7206ba3e00d8e33d8f819c3ee17bb83f58b68a3e5e4e4b3e257fb13d54d1a33ef8cc223e2cbdf93e3bab5240dd229d3fc9992f3d01dadd3ec722033a1abda93d9d96cc3e0e902d3f52a9f33e6317aa3e63b1223f5733143f352c1b3fa52f263f805d083dddf511403da10f40f6c3c83ed079463f4ebb253f1074603fef26bb3ecc305f3e99f85940eb01c83fb890983ee616433f775a693f05c5fd3e92362f3f62adcb3e47020a40bc04493cf5dd813f6341ee3d5df2a03e0000000040f4183eec8211403603843f7077e33fcd899e3e0553a03fccb159405b96493f5456903e0000000074be4f3f1646313e1344263fde99443e8007aa3eb4f69b3db728423e6fd9963f05809b3ee68fc43f66fdb43e0a6ec13f5f79f33fe8151d3f59e7293f76d6e93d852e22405247d73e78943c3ee6de3c3d55a13a3f6a90933f0ab03f3e5e34713ee644ce3dd9a4ed3f4653213db4a2233fe3f9014005f7a73fa2821b3ff262903fa872383d4c964d3ec2721d3faf01af3e827e933e9bdf533cf36dae3f23b89840c457793f032eca3fbc19b13ef0bb6c3da856003f000000003489d73bbbde4e3f74a48040d65ec23d25182b3f0a851e3e2304803f5b00ba3cb60b3f3fa75c0a40f079f53e8579493f1a5e2440f954a13c00000000ad71143da38f763f4d0c2d3f1f7fb53f80ffe33f8d79683bffa0153fafe7353f98e7124012c7b03fb70a553fdb4c45402fe9733e95214a3f33d3134018d28e3d5b57093f2f9ce63fea7edf3ee343d03fee141e406c6a863dfb5b033e5f50213d36c8564009d3533fca99353ec53d633f3f07183f0d6b424006e9803dbb9ac73ceab17e4055fc863f1e97d13dc460ec3e3617233f91a5b63e052af43c16b08c3e02a8143ffa9d8f401338803d04ad833e41da0e3bf8489b3f493a4c3ff2dfe13f877242404e05033d09e732402fb00d408162a13fa5c9453ec1e72e3ff0358c3d3f78d13fcc67b13f1aadc43e10c7814040f1c53fbbd2303f54c78a3d1dea963edf1e9a3f0990c23e88ac593ea3e8e43e7fdcc33fc812b83eac02b03fac67c53f8d4db440a560993f90308f3e4c20483d5ac1023eb963f73abf18463f14734e3f1c228f3c60319c3e410df23e8ce1c63f000000007c9bc43d840e444000000000bf42823e3dfb123f18a0083fca75ce3f5e6ad23f1b41403f631b224083a3f63e288b0d3f9f222d3f00000000965c0140d50eb13defd0903f1e36123d9fc6c63e0736e53faf4a1a3e5b2d3e40366e903df00ca63d04d3423da0240340492fd63f8051023f2273663fa79e4c3d67613e40b079033d72cac93e98910540e72f2e405933ba3b8d26563f2dd19e3fb090b53f3780a83db3c4d73eb7ed4f408ccd0740ac5f583f72e8ce3e369bc93dc05bc33eff658140a05f083feade1e3fd662fe3bfbd1ae3f3d3da43f2114653d0498f63f43a3bf400723433fb6768c3e5286623fab24853f8503e73f612fd43e04f8623f703a803e7cfa853fe9bc813f9146a93d5e74ac3ec356af3f5c7d903b6e3f8c3f000000009a9bfa3ef848ae3e194f4a3f122e3c3e5b39213facc8573f2210523f363c7b3e6e29783e21cb193da636d73f1a5c0a40bb1cdb3ed230973fe136e63eea12b13d7267493fff47833ff40fdb3dc7e5633f11e0683fd656ca3f04c18d3efc6fcf3ff0ec473f2faf3f3f10060b3e4109f33ee2835b3c34538d3fa86d5740b6504a3c1907b93fb22e3a3e79accb3e5fedbf3e7fa8903d7909303e4463ad3e7f09643f4edd7c3f7913393fe822163f7f3c034039b3373fa7949a3f07a7bd3f347b7d3e49c54b3e7824d23f8710b13d44bd14400ad4f63f88ae393e7388f33d07a64e3e3b400d3f46c1023f9634b03f9f32033c0800253f28fe833ea1e9c63ddb37453f3396533f08d3a43c2c72543f9be3ec3ffcd7a340f4c2cd3ffc4b3b3de32b133fa1c10e3fdae2f33e68cbd93f0c640540ec071940a8659b3d5bd1793fabcadd3ece562a4087010f3e5dcb913f15c27f3e38ddc63def334d3f7901843f1402743e1422ff3f184b6a4045c4703f3735eb3e4758503f093c033f45e5223d4952d73e9939253f146dc13d9fdf293f94891c404efa843f346e623f49b9a23f44536f3f34d46c3e5e28783f00000000f92b8d3e6a09403f1984163e83f7a73ef833ae3fc8f52e404e42993fc761753fac9fa93ec9c4a53e5517bc3f1447463bc48a263ed979613f4726f73e36b6bb3c0d9c3c3d6c5b953f6b222b3cf46afe3e`, - }, { - name: 'Patio Light', - price: 120, - image: `35d4113f32cdd43dc803043e85ff453da392643fa1b3da3e12cc113e5b99db3e7401653fe23d213f2be8953f54c82d4080137e3d23bc953e2392843e2317104000000000ab58703f44826040aed8a53fce99c33f9146a03e2284283f0a659c3edd996a3ef619ed3f5edac53e0923853ed974403f3b13fe3f5b81b03e01ac1c3e6e0de63ec81f723f2a408c3ec8398b3f98455d406e52333fb43cb03f0d6fb53de6910c3f9a54843f92ad0e3dc788bf3f720c673f778b643f2354cc3f265b0d3f3337983edea2413e537a1040486a6b3f2e567b3f1668db3fbc6152409df0cd3f314d9c3db2f9893fc5c3053f72cca23f4760d13e04faa83f95f9543eab420840548f0b3f0923143ec5a6b73ff85aa33eb201aa3e5617fc3eaa557f3f190d3c401b77fb3f8735443f03a3853d9503f33f2284be3e10c8253f3847503faae4753f33109e3f15c6df3ff6b4d63de8310d3f059932405487293fe86c923bda5a373e479c3d3eea87cf3fd8367b3ff6c76e3f660de43cd0d69a3eed00163f9d0e0e400a175c3f9fd8a53d00000000e8be963ef83a673fda9a933fe1651540b9a34e3efc29df3dcada8d40a85cac3e14150a3fc800af3e39019b3f4d048d3fa3dc6d3ff0730f40c95bbc3eeaf9ce3f20b1203d801fe03cd1fbc93facb54a3fcd915a3f4457a13eac1cae3f132b193fe58b5a3ec7a57f3fd6ce9f3e18988c3f485ae83ebd88f23e37832f3ff981c83ee23f2240db66a03f5ee4343efeac033fe7021a3fbe47a13e7265f13ef0d47a3f10541d3f5fbfca3db286dd3e7a30983e37e4f63e409dbc3f52c5233e4159323f61a2254068f6183fe179483e5a38453f459a2b4095c0a83f2574b93ecd5fb63d1c00a43ee86f513f7046f03ff34eb63fa35ea03e814cb03fbc4aa93fdc7d1b3f6528993f72d1673ff7b8c23fdb0e8e3e58643c3f3fff293f59ab413ed65a013fc4eab53f7b75373f6a2d453f2637283f03d8563f28bdad3c38a1b33e112c313f90e2243f0156ac3fccd5803f34faf73d7bd4803e3b04cc3c7779a73ee6e1c93feed9323fc1128b3d12151f400de8b53d6f09cc3d0d02373fc850f43e79c7a83dc573263fe35c5d3fc9bfd53bb26aa63f96d1a43ddb6d163e2c7eca3fe6ad363f9963283f0d09983f7423063dc522333f8a02573f851d2a3f39f9fe3d0169143d4cc59a3e16f0fa3fa1ad213fb937153f23ded03dc4e91f4078c7893f000000007d0f223fc54f933ee108c13e9bace83fcba50f409223d33e8b8e993fb336db3edd442e3f2555c13ed40cd93ea618043e901ce03f0573da3d5573293f388e023ef6c6a33c63db193edabb334036be2b3fe24c893f22bdac3fff31bd3e087bb63f647c9f3ef4e95d3f30dead3ff9747d3ec386263fcf2c0e3f74d9ec3e6cfb9b3f09c2b23e80e3a13f1988733e15b7ca3e689b1e3f4716933f840ae03ea1a52540ca2b533f227c883e63c1073e2558ca3e70e9a83e1668b13f133e213fbb9fbd3f0d08723ff9f1553f2f09f03eac3cbc3e8d1b9c3f07e81e40c85e213ddd4109403fbe863eda0f3a3e0462cc3f3768ad3e140ebe3e5b3ab73e94cd1340ea89be3fe647483d7c150540830b173fd4bf1b404379093fb73fee3d6c37133f1d80ca3e9a99653fc979aa3f8ffb123f2a52143fb971373f9807923ff6ea3e3f5a05e73eaca1793e21db3440f7c0e13e784c514059cf943e33d3553f0fb2893cc4c655405f0e3c3f40b11340dea3233f52301b3f76c8ef3f9d1aa93e9ac4553e807b793ea599573fd9872e3f805b6440e69cf23d95d1ba3e22150d3ff4c3fd3e165f3740213e803d4813bd3f2c33df3edb8b8e3ef6de2d40af40d33f7949813ef011613bdae2e13f454d8b3e684c763fd22a953fb699963e322f583fd98b1a3f2f39283f03f1733f4d51f33f3c253d407601643e14282a3f3fb42e3e4d03263f24d0963ff962154001f0823d38d7f73f03dba73ed430893d3f8e263fe5319e3ee5c5de3f99d39d3d4e42404061ae2240918eb43fd6b7443c0cd1a53f77a7c240d6ad223f990db73f7dde3f408764ce3f3facc23f837dbb3e3aa39a3ea1b9de3c10505a3f7b7e443f03187a3f7c23b63f3952523ff8121d4062f7733fa331fb3f6825ee3c32bf0a404441b63f4d9c4f3d12ec7d3faffa853fbc940a3dae88823ff98b1c3f1b3e5a3f5158353e619bbf3db74e433fb9a81e3e096e5c3d2c7c7a3f5be0843eac75d13de194d23fe368a53eecd1903f417ceb3faf9fa13fca7dfb3f1157313fbb18d43e5d33ea3fd001af3eeec31f3e5f12333fd54b3b40129f993fabe81b4087fba83e11319e3fecc5013feaa4b23e79010e40a26dc33d4120b63f4409bb3f43a5473f9d0f533fc501913f3218673fda34833d7637fc3d1a70dc3fd6a8d93cfc859d3d18c7503f0c07a63fa2cf1f3fa7d2ae3f557a4d3e199ee93f944b723e8a30483c25ae3f4034b98e3ebc10263f5a5914401da23740f77cc73ef21a703f9f297a3ff63f8e3f25e7044021846f3f65a61c3f4c953b409ff8593fe56bb33e703bd03d2a84283e9a22c540cef5733d66873e409c4d963f896b373f4ab0a43e15555a3ec4053a3e3737f23eca13893fe17cb53f38d4943ffcaad23e0d4bb43f7492113f2ea7233fe56fe23efccec23f2245733e18c5c63ff678373e1422983f01e3ce3fea06323fd9258b3e3932cb3eaa2bcb3f5fd6073e90af3b3f2892f83ebd710a3eb4561440c1133c4021d3234007da1c3f7f2d1f3f39150640bf045c3fe337543c5d0b863f0a3e903fa5faee3fa27f6c3c6a3e673fa8891f3d7cb28c3fe132b13fb9d5d43fdea3b43fd9d7383edd9cdd3e85530f3c5a43dd3e2b151c3f6533b63ef8929b3fc2311f3ea534803e656dc93f`, - }, { - name: '2-seater sofa', - price: 400, - image: `a8cd873f83e1553fe701173f3fabc83c9fd6613f51aa343fb43b883ff173083f207d943ffa6e19401618a93ff600ff3fc410763f493d443f5d579a3f1f0ddc3f4e0bfd3d25fc2b3faf43453ed146783fb498713e486bcb3f8a7c6d3fe7e9aa3f59482b3f1c34013f03fdee3e9e412940035a313fa5967d3e7983043f1f93393f5220233f85d9ea3dd6eacc3db48e243ff22f414038947d3e3c784f3f381ac33ff128a03e51cfcb3f81716b3f3fddd83f3d5b063f3bf4f63d50a1a13ebb111040f7a3573e12d1963e78a2ba3f8d05053fe474103d3f03d53ec12b2a402ae43b3fb0ea613facf0573f032c0f3f2e22b83fdefebd3f631b6e3fddfc823e2816d43d0a2dab3f5e7e653f3f67423fda7bcd3e7f3cde3e75530f3f094e233e225bb43ee528113fc4de713ec0ab4b3ea6baad3fd3c19f3f68f4473d49b8c83e416bdd3e2c94673e948f893f7b8c4d3ebf903e4003837e3ea7eb633facd6fd3cb4930d3f32d705406237a63fc97c2c3e7ae4143e98b9ba3e5b4e2b3ea6e24d3f67d8053fc4f049401a59623fb426be3f9fcbff3e5904153f707dc63f811bbe3e21c9833fda22163f9fa9f03ef39a3d3d8c381c3e2e3d2e3f41453c40ae0f1e3f0b721f3f8afe9c3ddb492d3e1b72403fa6baa13f2a517340482af53e10213e3fdbfb7d3f014e473e283b2840a4289a3fcc29e83f1b6af73f484b043e8420de3fd4b5853ec48a9d3f3784aa3ee14a833d1556eb3f6d5b933f5f64ce3f908ebd3e1452493fc161cc3e0ad08e3e122aae3d15676640394cbe3fefc3d43e905dde3faf9c433e8622a23c9d04683ea009104052cbda3f24689d3e5ee3b43fb2b92e40000000004c87e13fc3f3ae3ec4f2af3e4720083f25763d3fa767323f8a506f3ee395c43f5e9107402819973e8a49033f806a9b408e8c883fe15a943f372dcc3e22ff1b3fde3bae3f21c9a33f2259803e07d15c3d8576fa3f4d45d63e6fdc3c408d41b43f7824fa3daefb853e1a6dae3d167ce73eb7b20b4054a0963e7db4c73e74f1484004fe7b3f29e31f3f0433183fa9191b3f7280573f91746b3d3d17263f1bfea23d833b1b40099baf3e22d58a40086bff3d794df73e56d56e40bd531c4034cc8b3f5801a83ed4efed3f18ec3d3f770e043d7b82823e12e90d3fa55f033f967fb13f14cdac3ff35e6c3eb30cd43d5272373ede6bdd3e283cd63e7663573f907ad83e21c31f40de97803faaed643f1266a93f5451153f375b433e9a86ad3f4eb6d63fb8aa233f75a21040a776723f83d4f23d5aaed93ee6405d3e49b2063fb465853f7e5a143fccc19d39a2e8283f700b023f58e1d03ee1a01b3e7d62ac3bbf1adb3c25f87b3ff9d2283e30daa73f7953203f23b8533f3cc0833fa593403f339ab03c143e733f9d28f03e19e5d23ff342a23ee1e1683e437e4f3e8cb9bf3e16cc2a3f40d7033fccb4bb3e22258b3fec446a3e9d0ba63f7f94e73efb7fd83f651bb13e894c883f18b45c3f9f0bfe3e11b0ea3e52bd813fb88d9d3d0574043fdb05ef3e3931eb3ed82f4c3e7c688f3b28be013f988eb53e5db9e03ff755423feede163f8af6253f2adb21401259b63f3082963d2c7aa63fc7cfa83ef2cdf63d6c88133fb6541f3fbbf2c73ff0a2ec3fac75b13eb92810407cd5a53efda7003eb9604e3ee31fa93f32da173fdbd0383e402d2d3f964f2a3f68b0c13e45c81a3f94f4f03fc1ada33ea363bb3d4459e03ced6a023eb724f33e66a7093faa88cb3e64e2153f88feb83ff31d003e4708933fca7bf63fdf02c23eae2fb03ec7db133f4ec5153f50f5b13f5f25423f157f8c3ef9e8fd3e3991353fa1eb243ed4703140ef72af3e2a2ba43c386b143e8cd4843ea74b443e6895f13c7f2d0b40da5731405b33653f0358e93f799ba83e89b4ef3ed96ac23fe352463f6b9d823fb685aa3e3cd3e13cb2fd1540cde8fc3ebb39103f5e3ac03e0e6dcd3f78be373f7759bf3f33e6833f94309f3f50b4653f00000000f77f0840d619cb3ff0b3353fff7dec3e50e2483f95693b3f47b43d3ff7183b3f2846e03f6b0e4b40bdd7423f81eea53fb498853e10b02240b914253f3495443d10e8323f7433483ec569773fbf90f83fb450063e2c89373ecaa807406569fa3e1d708f3fade6143e2b07943fa77e9340108d2540a57d7a3e7854093f0729643f55e22d3f77020f3e946ed33ff9f025402118413ea7541f3f3792a63dbdf4933e7cd6363eca9e773faed1813f0715753e016df83de1730b3f7084113e66893c3fff723e40571882405306903f7b988f3fde962a3fb7a4a33ee17ce23fe1a02e3f8cf18c3fa3d9ea3f3d7ccb3facb2873f8d0e793fc7e02c3f1f4de63f9c2b1b3f30345c3f8e42823d49aab43d9b56e63f61add23f9072b93d7013dd3d47994a3fdd49b33ef83ea03ec813c23f2ab0233e3707e93f142e4e3efbf68640ef4bb23f053fd23f41829c3eb8404a3f5d41833e43d6a73e6e74063ba86f813d3fe3d43d1eb2af3f8841c23f1fa06f3e3f11e04022512b3f34ccb13e9ee8b23d7994c03fbcf8ba3f925fea3fd43ca53f3c66ca3e0e2bad3ca22fee3f70ba733f4ad3713e19ff6f3d4ca77a3ce2b3623fd18ef13e7718d93ee0be9e3f78211f3fac1c1640147741401f697c3ef5ff193f4c20283f01ea9d3f74903c40d9decf3f67420a3e4a1e7f3f4402aa3ee3f8413d9e3ec73f5a22d83f55700a3f48cabb3e99feff3e580d813f5581eb3f59f5803fca4cad3fd6ba1b3f051fdb3e2284a53f4a9f174077eed03e3205163f0bb4243f70d1c43fc7e72b3f66590e40d5c2873f22f1283f8d6e713fc359c93e58c0943f8a66b13db2bfce3e5d28303dc8f7543f3fb0c73c2ddd8c3f94db23405042443f6241a33f37407d3d`, - }, { - name: 'Comfy Chair', - price: 200, - image: `5101003f8b25923f1db69e3f1465113fdec3993b1000813f321fb33cc1d53f3ff9e68e3f2ec10840c869023f4082b03fe1711b3fd0fcff3debc3753e7086be3f1f2f8d3ec3acbf3f5059433fc8e2e43eae18093e6a935c3fafd41f3f3b48fa3d2e2a8a3f00000000688ef93e88a4083fe8439b3e33428a3f2b2ce13eb09d263f8c44113eb0fed83e907fd43eb90bca3d38c21c3fe1b4c23e87426e409de2a23da3030b3f0f0e8f3fb919283e414c883f98c7ca3e4cbcdf3fe767a03e4148683d433802400059173e6cb4c03f362f1240db64b53e9560613fa155c03fd5a7bd3f6a7db83e167a843f9bb5433ebfdcd33f3c72383f8dff673e785d9a3e6bf5223ef08e8e3fc4fc153fba7a8d3f4cf9bd3e32ab593e3b8f1e3e03e3813fb896a73f3f7e473f157b463e59306a3fe8ff973cc794b33f3fa74c3e14af573e1f9a85402631143e83fb8b3f88a8b73af8f9013f4df51540a799eb3e45fa1a3ef6d9223f67ab8b3f3faa6a3e951fbe3fbf33903fea9a853e3d10123e66435e3e5599c43f44b90a404869bb3e5f908f3e511bbf3ed111713dc77bc03d17ac0e3fd63b8f3f95c1353d826f83409d0e103f8965033f9e9d313f9e0ecf3f65760a3ed57a703db26e0d3e08f8bd3d6ea78d3f21428f3e65a7803f12c2df3f7b97083d6e8abb3f70af883f197a753d7b3e4e3e8096023ef760803fbde3283ccad13e409eb84f3e3ff1503e5bc0833fea91bd3e7377d93f039fe23f764e2e3d4eb4e73e65c1b03e32989b3f0a1f133d4a63833f2c8ea43fcc8a253fd84e6c3e0c59883e98b1713d3435653e22673a3e4d00eb3c7dff163fc0a1b03ed98f493f1a251f3f08d9783f83b6dc3fdf001a3f6149983e8083f33eb816643f1569023ff33dc63d5ebcb73e874a6b3e50d2873e28798f3e89764a409138da3b6a9ad63fa7f8503e14f51c3d49ca793e44015c3fbf65603eb9b2f93ec8bb8a3e1822ee3de17bfe3fd93a243fdeba0e3ef2f7553e657d8a3fa86ca53e9e64613e22a20c3e5e55af3e2eb2b03f928c323fccfec63ee880423dd2b9e63d7d602e3e2a288b3e2525a93d9abf483d0ccfaa3e7f0ff23daa57c340cef7d03d256abe3e44d32d3f1fc9703fe3874a3f847eb23f386bb73ff0dd3b3fd474bf3f085ced3d2a10b23ea25dd13f98b39e3fada5803f3257853f8f830d3fe81f9e3ebf50c33e72e6c43fe154c23fdb64ec3fb820463da1fc403e39809d3e482ed63f4d3fc83dc7cf9c3f59f4c63eb56ba23e9ab9f63ef423ba3f674a793f3f055d3d1d7c063ec4b7303ff32c5f3f0a18ca3ef87d5a3e513a1e3fec22f73c2f11263f6eefb13ed98a7e3f386e243e8cdd12406135023f32dd7e3ff9dd963d2a77393d839d6a40eabf193cda02ad3e0838433f65beab3fa68b043ed03d653f16ac483d9b43c33daf02f23ba565863e66568a3f8f3da23c4ed8ee3f5ed0223f7682693f7cece53edb2e6b3fc4ad293e829c183f2146003e6c600c40a684bf3f49e96e3dc126313fe24ec53ededa783f7823a13de7bbe83e9d39583f9f3f333e04c7613f61d4343f61a3463d66cf583f6cf0b13ee1ac463fe5d7843fb9fc353de59aeb3e509cc23e11bf7c3d447f103f9ffde43fe1dc3a3eb34a183f301e3c3f7feb453c9242683ec4c12b3e82e3133f557e6f3c2f2c443f8a1b01409042893f943d853f4e114d402ab7a23f5d09483f1d3f0f4083ef623ed61f433ea544d43e0e92fe3e38f0283fea7d033fb8288a3e0dcddf3fb78cde3e28ab2f3f84854340548b473fc758013b78449a3ef5b6803f9b65ce3f96d5603fd2928e3fe15424407479e53dff78c13f395f0440f025b73ef9b2a33e6ba2373fa51f5a3f30f1143f895eaf3efbdb283f22ae333e95d2e73f45dce33db2070a4091e91d3ef8d98e3dd9cfd03fb46e7c3e2fe8433ed15dc53e7092893fea6e853f48a48a3f2646ea3f63e98a3eb31c2d3eb722593eedc1883ed26b8e3e114d6a3dac019e3f4e9f943f1567b23f6f6a254079d3243fa5ee5b3e70fc0e3f5b894740162a873f0e14d73f625f0e3fecf84f40fc360d3f22adf73daa6cad3e30212c3f01a68a3ddae0393f3248703de8afad3dabd0e23f7949083ec86c7d3ffd2dbf3f091eb73e5f6d9c3da6b7223e6b3edb3e150c9d3e81363e3fb420be3f9de9ba3bf3dcdd3e8f99113eb9cafe3d2ceb3b3fa558ac3f7356063eb236f93e1d4cdf3ecc5db53ec4b2423ea2b5823fdb19413e4a57603f8bac1c407d57c53fe2e25b3f84399e3fbcf9973fdd93153f498da93f3c53623ffb929e3eb7a6343fd4f8f63f768dd13f885d153fcdd11440befe8a3e6ee900406d75013f95e97f3f54b4303fb37a953fda9ce23de70c3c3f747eb13e6efe913de2cf613e68a5633e19cb633f1a228f3e0c71b23eb5718e3e9d06ec3faf5c2f3e5907103f592ccb402128463fc8e2e93e6ed22e3ff61d243fef81f43f9535b03f84a22c3f86689d3fc3050a3f7d209a3e28ae033f8c62883f486c283f39a6d93d44d28a40d4cecd3d019c363fefbeaf3f7e30923eb28d033d30db343e77a3f83ed185023f18fe7f407690d53ed066213d58ad983efda3723f2b6ab83d6adee33ddea5ed3d3f87813f40cc033f48cb953fffba163eac9bca3d74c7923f262fdd3ee5080a3fc40efb3e99692d3f80573c3d9622933fa2b8aa3e186afa3f5dfda63f6b9201402212e73f6fa8033ffb78123fd70da43f07899d3cc171b13fd1f8f83a68ddf33f4d84e43db9ac8b3f1b6b1940d171503f224e153e6a9c773e31650b3f5baa283f30c2bd3b00000000623ad03f70482b3da918923f7c6cc23de80dd93fc586f33e956e743f26a0a93e61c4b03e2a787e3cd9c7bd3efbe1d73fdb3ca13e5a601f3f1fc9623e`, - }] diff --git a/spec/helpers/example-data.ts b/spec/helpers/example-data.ts index 1e1a30d7..1b77edf6 100644 --- a/spec/helpers/example-data.ts +++ b/spec/helpers/example-data.ts @@ -59,8 +59,8 @@ export const SOME_MORE_STRINGS: Array = ['charlie', 'delta', 'echo']; export const SOME_MORE_STRINGS_JSON: string = JSON.stringify(SOME_MORE_STRINGS); export const SOME_MORE_STRINGS_JOINED: string = SOME_MORE_STRINGS.join('|'); -export const A_BUFFER_VALUES = [1, 2, 3, 4, 5, 6] -export const A_BUFFER = Buffer.from(A_BUFFER_VALUES) +export const A_BUFFER = Buffer.from(`52b85e3f9a9919becdcc0c3f8fc2f53c333333bf5c8f02bfae47613f295c0f3ecdcc4cbf9a9919bec3f5a83e0ad723bc`, 'hex') +export const A_BUFFER_VALUES = [0.8700000047683716, -0.15000000596046448, 0.550000011920929, 0.029999999329447746, -0.699999988079071, -0.5099999904632568, 0.8799999952316284, 0.14000000059604645, -0.800000011920929, -0.15000000596046448, 0.33000001311302185, -0.009999999776482582] export type SampleEntityData = { aString: string | null;