
Research
/Security News
11 Malicious Go Packages Distribute Obfuscated Remote Payloads
Socket uncovered 11 malicious Go packages using obfuscated loaders to fetch and execute second-stage payloads via C2 domains.
synchronous-autocomplete
Advanced tools
Fast, simple autocompletion. Also supports Levenshtein-based fuzzy search. Uses precomputed indexes to be fast.
npm install synchronous-autocomplete
Let's build a simple search for our fruit stand. We assign a weight
property to each of them because some are bought more often and we want to push their ranking in the search results.
const items = [ {
id: 'apple',
name: 'Juicy sour Apple.',
weight: 3
}, {
id: 'banana',
name: 'Sweet juicy Banana!',
weight: 2
}, {
id: 'pome',
name: 'Sour Pomegranate',
weight: 5
} ]
Let's understand the terminology used by this tool:
Hey There!
, you may process its name into the tokens hey
& there
.ther
(from the search query Hey Ther
) partially matches the token there
.In order to be as fast and disk-space-efficient as possible, synchronous-autocomplete
requires five indexes to be prebuilt from the list of items. Check the example code for more details on how to build them. For our example, they would look like this:
const tokens = { // internal item IDs, by token
juicy: [0, 1],
sour: [0, 3],
apple: [0],
sweet: [1],
banana: [1],
pomegranate: [3]
}
const weights = [ // item weights, by internal item ID
3, // apple
2, // banana
5 // pome
]
const nrOfTokens = [ // nr of tokens, by internal item ID
3, // apple
3, // banana
2 // pome
]
const scores = { // "uniqueness" of each token, by token
juicy: 2 / 3, // 2 out of 3 items have the token "juicy"
sour: 2 / 3,
apple: 1 / 3,
sweet: 1 / 3,
banana: 1 / 3,
pomegranate: 1 / 3
}
// In order to create smaller search indexes, we use numerical item IDs
// internally and maintain a mapping to their "real"/original IDs.
const originalIds = [
'apple',
'banana',
'pome'
]
Next, we must define a function that normalizes search input into a list of fragments. Consider using this simple function:
import normalize from 'normalize-for-search'
const tokenize = (str) => {
return normalize(str).replace(/[^\w\s]/g, '').split(/\s+/g)
}
Of course, you don't have to calculate the tokens & scores! Instead, use buildIndex
to generate the data:
import {buildIndex} from 'synchronous-autocomplete/build.js'
const index = buildIndex(tokenize, items)
Now, we can query our index:
import {createAutocomplete} from 'synchronous-autocomplete'
const autocomplete = createAutocomplete(index, tokenize)
autocomplete('bana')
// [ {
// relevance: 0.6666665555555555,
// score: 0.8399472266053544,
// weight: 2,
// } ]
autocomplete('sour')
// [ {
// id: 'pome',
// relevance: 1.8333335,
// score: 3.134956187236602,
// weight: 5,
// }, {
// id: 'apple',
// relevance: 1.2222223333333333,
// score: 1.762749635070118,
// weight: 3,
// } ]
autocomplete('aplle', 3, true) // note the typo
// [ {
// id: 'apple',
// relevance: 0.22222216666666667,
// score: 0.3204998243877813,
// weight: 3,
// } ]
const index = buildIndex(tokenize, items)
const {tokens, scores, weights, nrOfTokens, originalIds} = index
tokenize
must be a function that, given a search query, returns an array of fragments.items
must be an array of objects, each with id
, name
& weight
.const autocomplete = createAutocomplete(index, tokenize)
autocomplete(query, limit = 6, fuzzy = false, completion = true)
tokens
must be an object with an array of internal item IDs per token.scores
must be an object with a token score per token.weights
must be an array with an item weight per internal item ID.nrOfTokens
must be an array with the number of tokens per internal item ID.originalIds
must be an array with the (real) item ID per internal item ID.tokenize
is the same as with buildIndex()
.Protocol buffers (a.k. protobufs) are a compact binary format for structured data serialization.
import {encodeIndex} from 'synchronous-autocomplete/encode.js'
import {writeFileSync, readFileSync} from 'node:fs'
// encode & write the index
const encoded = encodeIndex(index)
writeFileSync('index.pbf', encoded)
// read & decode the index
const decoded = decode(readFileSync('index.pbf'))
If you have a question or have difficulties using synchronous-autocomplete
, please double-check your code and setup first. If you think you have found a bug or want to propose a feature, refer to the issues page.
FAQs
Fast, simple autocompletion.
We found that synchronous-autocomplete demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
Socket uncovered 11 malicious Go packages using obfuscated loaders to fetch and execute second-stage payloads via C2 domains.
Security News
TC39 advances 11 JavaScript proposals, with two moving to Stage 4, bringing better math, binary APIs, and more features one step closer to the ECMAScript spec.
Research
/Security News
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).