Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

svelte-algolia

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

svelte-algolia - npm Package Compare versions

Comparing version 0.2.7 to 0.2.10

actions.d.ts

26

actions.js
export function onClickOutside(node, cb) {
const detectClickOutside = (event) => {
if (node && !node.contains(event.target) && !event.defaultPrevented) {
node.dispatchEvent(new CustomEvent(`clickOutside`, node))
if (cb) cb()
}
}
document.addEventListener(`click`, detectClickOutside)
return {
destroy: () => document.removeEventListener(`click`, detectClickOutside),
}
const dispatchOnClickOutside = (event) => {
const clickWasOutside = node && !node.contains(event.target);
if (clickWasOutside && !event.defaultPrevented) {
node.dispatchEvent(new CustomEvent(`clickOutside`));
if (cb)
cb();
}
};
document.addEventListener(`click`, dispatchOnClickOutside);
return {
destroy() {
document.removeEventListener(`click`, dispatchOnClickOutside);
},
};
}

@@ -1,1 +0,1 @@

export { default } from './Search.svelte'
export { default } from './Search.svelte';

@@ -1,178 +0,153 @@

/* eslint-disable no-console */
import algoliasearch from 'algoliasearch'
import algoliasearch from 'algoliasearch';
const defaultConfig = {
partialUpdates: false,
verbosity: 1,
matchFields: [],
settings: {},
partialUpdates: false,
verbosity: 1,
matchFields: [],
settings: {},
};
// Partial<T> makes all keys in T optional
export function deepEqual(obj1, obj2) {
return obj1 && obj2 && typeof obj1 === `object` && typeof obj1 === typeof obj2
? Object.keys(obj1).length === Object.keys(obj2).length &&
Object.keys(obj1).every((key) => deepEqual(obj1[key], obj2[key]))
: obj1 === obj2;
}
export function deepEqual(x, y) {
return x && y && typeof x === `object` && typeof x === typeof y
? Object.keys(x).length === Object.keys(y).length &&
Object.keys(x).every((key) => deepEqual(x[key], y[key]))
: x === y
export async function indexAlgolia({ appId, apiKey, indices, ...rest }) {
const client = algoliasearch(appId, apiKey);
const config = { ...defaultConfig, ...rest };
if (config.verbosity > 0) {
if (config.partialUpdates)
console.log(`svelte-algolia: Partial updates enabled`);
console.log(`svelte-algolia: ${indices.length} ${indices.length > 1 ? `indices` : `index`} to update`);
}
try {
await Promise.all(indices.map(updateIndex(client, config)));
}
catch (err) {
console.error(`failed to index to Algolia`, err);
}
}
export async function indexAlgolia({ appId, apiKey, indices, ...config }) {
const client = algoliasearch(appId, apiKey)
config = { ...defaultConfig, ...config }
if (config.verbosity > 0) {
if (config.partialUpdates)
console.log(`svelte-algolia: Partial updates enabled`)
console.log(
`svelte-algolia: ${indices.length} ${
indices.length > 1 ? `indices` : `index`
} to update`
)
}
try {
await Promise.all(indices.map(updateIndex(client, config)))
} catch (err) {
console.error(`failed to index to Algolia`, err)
}
}
const updateIndex = (client, config) => async (indexObj) => {
const { partialUpdates = false, matchFields: mainMatchFields } = config
const { name, getData, matchFields = mainMatchFields } = indexObj
let { settings = config.settings } = indexObj
const index = client.initIndex(name)
const data = await callGetter(getData)
// if user specified any settings, apply them
// if the index doesn't exist yet, applying settings (even if empty) will create it
// see https://algolia.com/doc/api-client/methods/manage-indices#create-an-index
const { taskID } = await index.setSettings(settings)
await index.waitTask(taskID)
if (partialUpdates) {
// get all match fields for all indices to minimize calls to the api
const allMatchFields = [...new Set([...mainMatchFields, ...matchFields])]
await partialUpdate(index, data, allMatchFields, config)
} else {
// if partialUpdates isn't true, overwrite old index with all of data
await overwriteUpdate(index, data, client, config)
}
}
const updateIndex = (client, config) => {
return async (indexConfig) => {
const { partialUpdates = false, matchFields: mainMatchFields } = config;
const { name, getData, matchFields = mainMatchFields } = indexConfig;
const { settings = config.settings || {} } = indexConfig;
const index = client.initIndex(name);
const data = await callGetter(getData);
// if user specified any settings, apply them
// if the index doesn't exist yet, applying settings (even if empty) will create it
// see https://algolia.com/doc/api-client/methods/manage-indices#create-an-index
const { taskID } = await index.setSettings(settings);
await index.waitTask(taskID);
if (partialUpdates) {
// get all match fields for all indices to minimize calls to the api
const allMatchFields = [...new Set([...mainMatchFields, ...matchFields])];
await partialUpdate(index, data, allMatchFields, config);
}
else {
// if partialUpdates isn't true, overwrite old index with all of data
await overwriteUpdate(index, data, client, config);
}
};
};
async function callGetter(getter) {
const results = await getter()
if (results.errors)
console.error(
`failed to index to Algolia, ` +
`errors:\n ${JSON.stringify(results.errors, null, 2)}`
)
results.forEach((obj) => {
if (!obj.objectID && !obj.id && !obj._id)
console.error(
`failed to index to svelte-algolia: ${JSON.stringify(obj, null, 2)}` +
` has neither an 'objectID' nor 'id' key`
)
// convert to string to prevent processing items with integer IDs as new in partialUpdate
obj.objectID = `${obj.objectID || obj.id || obj._id}`
})
return results
try {
const results = await getter();
results.forEach((obj) => {
if (!obj.objectID && !obj.id && !obj._id)
console.error(`failed to index to svelte-algolia: ${JSON.stringify(obj, null, 2)}` +
` has neither an 'objectID' nor 'id' key`);
// convert to string to prevent processing items with integer IDs as new in partialUpdate
obj.objectID = `${obj.objectID || obj.id || obj._id}`;
});
return results;
}
catch (err) {
console.error(`failed to index to Algolia due to ${err}`);
}
}
async function overwriteUpdate(index, data, client, config) {
const { indexName: name } = index
try {
const tmpIndex = client.initIndex(`${name}_tmp`)
// copy settings from old to new index
const settings = await index.getSettings()
await tmpIndex.setSettings(settings)
await tmpIndex.saveObjects(data).wait()
// move the tmp index to the existing index, overwrites the latter
await client.moveIndex(`${name}_tmp`, name).wait()
if (config.verbosity > 0)
console.log(`index '${name}': wrote ${data.length} items`)
} catch (err) {
console.error(err)
// clean up by removing temporary index in case of errors
await client.moveIndex(`${name}_tmp`, name).wait()
}
const { indexName: name } = index;
try {
const tmpIndex = client.initIndex(`${name}_tmp`);
// copy settings from old to new index
const settings = await index.getSettings();
await tmpIndex.setSettings(settings);
await tmpIndex.saveObjects(data).wait();
// move the tmp index to the existing index, overwrites the latter
await client.moveIndex(`${name}_tmp`, name).wait();
if (config.verbosity > 0)
console.log(`index '${name}': wrote ${data.length} items`);
}
catch (err) {
console.error(err);
// clean up by removing temporary index in case of errors
await client.moveIndex(`${name}_tmp`, name).wait();
}
}
async function partialUpdate(index, data, matchFields, config) {
const { indexName: name } = index
const existingObjects = await fetchExistingData(index, matchFields)
const existingIDs = existingObjects.map((obj) => obj.objectID)
const newIDs = data.map((obj) => obj.objectID)
// objects to be added/updated
const toIndex = data.filter((newObj) => {
const { objectID: id } = newObj
// object with new ID, needs to be indexed
if (!existingIDs.includes(id)) return true
if (matchFields) {
// id matches existing object, so compare match fields to check if existing object neeeds to be updated
if (!matchFields.every((field) => newObj[field])) {
console.error(
`when partialUpdates is true, the objects must have at least one of the match fields.` +
`Current object:\n${JSON.stringify(newObj, null, 2)}` +
`\nexpected one of these fields:\n${matchFields.join(`\n`)}`
)
}
const existingObj = existingObjects.find((obj) => obj.objectID === id)
// check if one or more fields differ, if so update object
if (matchFields.some((field) => existingObj[field] !== newObj[field]))
return true
} else {
// if user did not specify matchFields compare entire object for differences
if (!deepEqual(oldObj, newObj)) {
return true
}
const { indexName: name } = index;
const existingObjects = await fetchExistingData(index, matchFields);
const existingIDs = existingObjects.map((obj) => obj.objectID);
const newIDs = data.map((obj) => obj.objectID);
// objects to be added/updated
const toIndex = data.filter((newObj) => {
const { objectID: id } = newObj;
// object with new ID, needs to be indexed
if (!existingIDs.includes(id))
return true;
if (matchFields) {
// id matches existing object, so compare match fields to check if existing object needs to be updated
if (!matchFields.every((field) => newObj[field])) {
console.error(`when partialUpdates is true, the objects must have at least one of the match fields.` +
`Current object:\n${JSON.stringify(newObj, null, 2)}` +
`\nexpected one of these fields:\n${matchFields.join(`\n`)}`);
}
const existingObj = existingObjects.find((obj) => obj.objectID === id);
// check if one or more fields differ, if so update object
if (matchFields.some((field) => existingObj[field] !== newObj[field]))
return true;
}
else {
// if user did not specify matchFields compare entire object for differences
if (!deepEqual(oldObj, newObj)) {
return true;
}
}
return false; // neither new nor changed object, no need to index
});
// stale objects to be removed
const toRemove = existingIDs.filter((id) => !newIDs.includes(id));
if (toIndex.length) {
if (config.verbosity > 0)
console.log(`index '${name}': found ${toIndex.length} new or modified objects; indexing...`);
if (config.verbosity > 1)
console.log(JSON.stringify(toIndex, null, 2));
await index.saveObjects(toIndex).wait();
}
return false // neither new nor changed object, no need to index
})
// stale objects to be removed
const toRemove = existingIDs.filter((id) => !newIDs.includes(id))
if (toIndex.length) {
if (config.verbosity > 0)
console.log(
`index '${name}': found ${toIndex.length} new or modified objects; indexing...`
)
if (config.verbosity > 1) console.log(JSON.stringify(toIndex, null, 2))
await index.saveObjects(toIndex).wait()
}
if (toRemove.length) {
if (config.verbosity > 0)
console.log(
`index '${name}': found ${toRemove.length} stale objects; removing...`
)
if (config.verbosity > 1) console.log(JSON.stringify(toRemove, null, 2))
await index.deleteObjects(toRemove)
}
if (config.verbosity > 0) {
if (toIndex.length === 0 && toRemove.length === 0) {
console.log(`index '${name}': no updates necessary; skipping!`)
} else {
console.log(`index '${name}': done updating`)
if (toRemove.length) {
if (config.verbosity > 0)
console.log(`index '${name}': found ${toRemove.length} stale objects; removing...`);
if (config.verbosity > 1)
console.log(JSON.stringify(toRemove, null, 2));
await index.deleteObjects(toRemove);
}
}
if (config.verbosity > 0) {
if (toIndex.length === 0 && toRemove.length === 0) {
console.log(`index '${name}': no updates necessary; skipping!`);
}
else {
console.log(`index '${name}': done updating`);
}
}
}
// Fetches all records for the current index from Algolia
async function fetchExistingData(index, attributesToRetrieve) {
const hits = []
await index.browseObjects({
query: ``, // Empty query matches all records
batch: (batch) => hits.push(...batch),
attributesToRetrieve,
})
return hits
const hits = [];
await index.browseObjects({
query: ``,
batch: (batch) => hits.push(...batch),
attributesToRetrieve,
});
return hits;
}
{
"name": "svelte-algolia",
"version": "0.2.7",
"description": "Algolia server-side index updater and client-side search component for Svelte projects",
"author": "Janosh Riebesell <janosh.riebesell@gmail.com>",
"homepage": "https://svelte-algolia.netlify.app",
"repository": "https://github.com/janosh/svelte-algolia",
"license": "MIT",
"version": "0.2.10",
"type": "module",
"svelte": "Search.svelte",
"keywords": [

@@ -13,13 +19,31 @@ "svelte",

],
"homepage": "https://svelte-algolia.netlify.app",
"license": "MIT",
"author": "Janosh Riebesell <janosh.riebesell@gmail.com>",
"repository": "https://github.com/janosh/svelte-algolia",
"dependencies": {
"algoliasearch": "^4.10.2"
"algoliasearch": "^4.11.0"
},
"devDependencies": {
"@sveltejs/adapter-static": "^1.0.0-next.24",
"@sveltejs/kit": "^1.0.0-next.211",
"@typescript-eslint/eslint-plugin": "^5.8.1",
"@typescript-eslint/parser": "^5.8.1",
"ava": "^3.15.0",
"dotenv": "^10.0.0",
"eslint": "^8.5.0",
"eslint-plugin-svelte3": "^3.2.1",
"hastscript": "^7.0.2",
"mdsvex": "^0.9.8",
"prettier": "^2.5.1",
"prettier-plugin-svelte": "^2.5.1",
"rehype-autolink-headings": "^6.1.1",
"rehype-slug": "^5.0.1",
"svelte": "^3.44.3",
"svelte-check": "^2.2.11",
"svelte-preprocess": "^4.10.1",
"svelte-toc": "^0.2.0",
"svelte2tsx": "^0.4.12",
"typescript": "^4.5.4",
"vite": "^2.7.10"
},
"publishConfig": {
"access": "public"
},
"type": "module",
"exports": {

@@ -29,7 +53,6 @@ "./package.json": "./package.json",

"./SearchIcon.svelte": "./SearchIcon.svelte",
"./actions.js": "./actions.js",
"./index.js": "./index.js",
"./main.js": "./main.js",
".": "./index.js"
"./actions": "./actions.js",
".": "./index.js",
"./main": "./main.js"
}
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc