Comparing version 0.12.0 to 1.0.3
315
lib/index.js
@@ -1,26 +0,301 @@ | ||
#!/usr/bin/env node | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const { execFileSync } = require('child_process'); | ||
import { PagefindService } from "./service.js"; | ||
import { decode } from "./encoding.js"; | ||
const binaryPath = path.join(__dirname, `../bin/pagefind_extended${process.platform === 'win32' ? '.exe' : ''}`); | ||
/** | ||
* @typedef {import('pagefindInternal').InternalResponseCallback} InternalResponseCallback | ||
* @typedef {import('pagefindInternal').InternalResponsePayload} InternalResponsePayload | ||
*/ | ||
if (!fs.existsSync(binaryPath)) { | ||
console.error(`Binary failed to download — package expected to have downloaded the binary to ${binaryPath} during its postinstall`); | ||
console.error(`Do you have install scripts disabled for npm?`); | ||
console.error(`Try running \`npm config set ignore-scripts false\` and re-installing.`); | ||
console.error(`Otherwise, your platform might not be supported. Open an issue on GitHub!`); | ||
process.exit(1); | ||
/** | ||
* @type {PagefindService?} | ||
*/ | ||
let persistentService; | ||
const launch = () => { | ||
if (!persistentService) { | ||
persistentService = new PagefindService(); | ||
} | ||
return persistentService; | ||
} | ||
try { | ||
execFileSync( | ||
binaryPath, | ||
process.argv.slice(2), | ||
/** | ||
* @template T | ||
* @param {function(any): void} resolve | ||
* @param {function(any): void} reject | ||
* @param {InternalResponseCallback} response_callback | ||
* @param {function(InternalResponsePayload): T} resultFn | ||
*/ | ||
const handleApiResponse = (resolve, reject, { exception, err, result }, resultFn) => { | ||
if (exception) { | ||
reject(exception); | ||
} else { | ||
resolve({ | ||
errors: err ? [err.message] : [], | ||
...(result ? resultFn(result) : {}) | ||
}); | ||
} | ||
} | ||
/** | ||
* @typedef {import('pagefindService').NewIndexResponse} NewIndexResponse | ||
* | ||
* @param {import('pagefindService').PagefindServiceConfig=} config | ||
* @type {import('pagefindService').createIndex} | ||
* */ | ||
export const createIndex = (config) => new Promise((resolve, reject) => { | ||
// TODO: Validate `config` here, instead of waiting for the backend to throw an error. | ||
// Ideally we create a global Pagefind config JSON schema that (a subset of) can be used here. | ||
const action = 'NewIndex'; | ||
launch().sendMessage( | ||
{ | ||
stdio: [process.stdin, process.stdout, process.stderr] | ||
type: action, | ||
config: { | ||
root_selector: config?.rootSelector, | ||
exclude_selectors: config?.excludeSelectors, | ||
force_language: config?.forceLanguage, | ||
verbose: config?.verbose, | ||
logfile: config?.logfile, | ||
keep_index_url: config?.keepIndexUrl, | ||
} | ||
}, (response) => { | ||
/** @type {function(InternalResponsePayload): Omit<NewIndexResponse, 'errors'>?} */ | ||
const successCallback = (success) => { | ||
if (success.type !== action) { | ||
reject(`Message returned from backend should have been ${action}, but was ${success.type}`); | ||
return null; | ||
} | ||
return { | ||
index: indexFns(success.index_id), | ||
} | ||
}; | ||
handleApiResponse(resolve, reject, response, successCallback); | ||
} | ||
) | ||
} catch (err) { | ||
process.exit(1); | ||
} | ||
); | ||
}); | ||
/** | ||
* @type {import('pagefindService').close} | ||
*/ | ||
export const close = () => new Promise((resolve, reject) => { | ||
persistentService?.close(null); | ||
persistentService = null; | ||
resolve(null); | ||
}); | ||
/** | ||
* @param {number} indexId | ||
* @returns {import ('pagefindService').PagefindIndex} | ||
*/ | ||
const indexFns = (indexId) => { | ||
return { | ||
addHTMLFile: (file) => addHTMLFile(indexId, file), | ||
addCustomRecord: (record) => addCustomRecord(indexId, record), | ||
addDirectory: (dir) => addDirectory(indexId, dir), | ||
writeFiles: (options) => writeFiles(indexId, options), | ||
getFiles: () => getFiles(indexId), | ||
deleteIndex: () => deleteIndex(indexId) | ||
} | ||
} | ||
/** | ||
* @typedef {import('pagefindService').NewFileResponse} NewFileResponse | ||
* | ||
* @param {number} indexId | ||
* @param {import('pagefindService').HTMLFile} file | ||
* @returns {Promise<NewFileResponse>} | ||
*/ | ||
const addHTMLFile = (indexId, file) => new Promise((resolve, reject) => { | ||
const action = 'AddFile'; | ||
const responseAction = 'IndexedFile'; | ||
launch().sendMessage( | ||
{ | ||
type: action, | ||
index_id: indexId, | ||
file_path: file.sourcePath, | ||
url: file.url, | ||
file_contents: file.content | ||
}, (response) => { | ||
/** @type {function(InternalResponsePayload): Omit<NewFileResponse, 'errors'>?} */ | ||
const successCallback = (success) => { | ||
if (success.type !== responseAction) { | ||
reject(`Message returned from backend should have been ${action}, but was ${success.type}`); | ||
return null; | ||
} | ||
return { | ||
file: { | ||
uniqueWords: success.page_word_count, | ||
url: success.page_url, | ||
meta: success.page_meta, | ||
} | ||
} | ||
}; | ||
handleApiResponse(resolve, reject, response, successCallback); | ||
} | ||
); | ||
}); | ||
/** | ||
* @param {number} indexId | ||
* @param {import('pagefindService').CustomRecord} record | ||
* @returns {Promise<NewFileResponse>} | ||
*/ | ||
const addCustomRecord = (indexId, record) => new Promise((resolve, reject) => { | ||
const action = 'AddRecord'; | ||
const responseAction = 'IndexedFile'; | ||
launch().sendMessage( | ||
{ | ||
type: action, | ||
index_id: indexId, | ||
url: record.url, | ||
content: record.content, | ||
language: record.language, | ||
meta: record.meta, | ||
filters: record.filters, | ||
sort: record.sort, | ||
}, (response) => { | ||
/** @type {function(InternalResponsePayload): Omit<NewFileResponse, 'errors'>?} */ | ||
const successCallback = (success) => { | ||
if (success.type !== responseAction) { | ||
reject(`Message returned from backend should have been ${action}, but was ${success.type}`); | ||
return null; | ||
} | ||
return { | ||
file: { | ||
uniqueWords: success.page_word_count, | ||
url: success.page_url, | ||
meta: success.page_meta, | ||
} | ||
} | ||
}; | ||
handleApiResponse(resolve, reject, response, successCallback); | ||
} | ||
); | ||
}); | ||
/** | ||
* @typedef {import('pagefindService').IndexingResponse} IndexingResponse | ||
* | ||
* @param {number} indexId | ||
* @param {import('pagefindService').SiteDirectory} dir | ||
* @returns {Promise<IndexingResponse>} | ||
*/ | ||
const addDirectory = (indexId, dir) => new Promise((resolve, reject) => { | ||
const action = 'AddDir'; | ||
const responseAction = 'IndexedDir'; | ||
launch().sendMessage( | ||
{ | ||
type: action, | ||
index_id: indexId, | ||
path: dir.path, | ||
glob: dir.glob | ||
}, (response) => { | ||
/** @type {function(InternalResponsePayload): Omit<IndexingResponse, 'errors'>?} */ | ||
const successCallback = (success) => { | ||
if (success.type !== responseAction) { | ||
reject(`Message returned from backend should have been ${action}, but was ${success.type}`); | ||
return null; | ||
} | ||
return { | ||
page_count: success.page_count | ||
} | ||
}; | ||
handleApiResponse(resolve, reject, response, successCallback); | ||
} | ||
); | ||
}); | ||
/** | ||
* @typedef {import ('pagefindService').WriteFilesResponse} WriteFilesResponse | ||
* | ||
* @param {number} indexId | ||
* @param {import('pagefindService').WriteOptions=} options | ||
* @returns {Promise<WriteFilesResponse>} | ||
*/ | ||
const writeFiles = (indexId, options) => new Promise((resolve, reject) => { | ||
const action = 'WriteFiles'; | ||
launch().sendMessage( | ||
{ | ||
type: action, | ||
index_id: indexId, | ||
output_path: options?.outputPath | ||
}, (response) => { | ||
/** @type {function(InternalResponsePayload): Omit<WriteFilesResponse, 'errors'>?} */ | ||
const successCallback = (success) => { | ||
if (success.type !== action) { | ||
reject(`Message returned from backend should have been ${action}, but was ${success.type}`); | ||
return null; | ||
} | ||
return { | ||
outputPath: success.output_path | ||
} | ||
}; | ||
handleApiResponse(resolve, reject, response, successCallback); | ||
} | ||
); | ||
}); | ||
/** | ||
* @typedef {import ('pagefindService').GetFilesResponse} GetFilesResponse | ||
* | ||
* @param {number} indexId | ||
* @returns {Promise<GetFilesResponse>} | ||
*/ | ||
const getFiles = (indexId) => new Promise((resolve, reject) => { | ||
const action = 'GetFiles'; | ||
launch().sendMessage( | ||
{ | ||
type: action, | ||
index_id: indexId, | ||
}, (response) => { | ||
/** @type {function(InternalResponsePayload): Omit<GetFilesResponse, 'errors'>?} */ | ||
const successCallback = (success) => { | ||
if (success.type !== action) { | ||
reject(`Message returned from backend should have been ${action}, but was ${success.type}`); | ||
return null; | ||
} | ||
return { | ||
files: success.files.map(file => { | ||
return { | ||
path: file.path, | ||
content: decode(file.content) | ||
} | ||
}) | ||
} | ||
}; | ||
handleApiResponse(resolve, reject, response, successCallback); | ||
} | ||
); | ||
}); | ||
/** | ||
* @param {number} indexId | ||
* @returns {Promise<null>} | ||
*/ | ||
const deleteIndex = (indexId) => new Promise((resolve, reject) => { | ||
const action = 'DeleteIndex'; | ||
launch().sendMessage( | ||
{ | ||
type: action, | ||
index_id: indexId, | ||
}, (response) => { | ||
/** @type {function(InternalResponsePayload): Omit<GetFilesResponse, 'errors'>?} */ | ||
const successCallback = (success) => { | ||
if (success.type !== action) { | ||
reject(`Message returned from backend should have been ${action}, but was ${success.type}`); | ||
return null; | ||
} | ||
return null; | ||
}; | ||
handleApiResponse(resolve, reject, response, successCallback); | ||
} | ||
); | ||
}); |
{ | ||
"name": "pagefind", | ||
"version": "0.12.0", | ||
"version": "1.0.3", | ||
"type": "module", | ||
"description": "Implement search on any static website.", | ||
"bin": "lib/index.js", | ||
"bin": "lib/runner/bin.cjs", | ||
"main": "lib/index.js", | ||
"repository": { | ||
@@ -10,14 +12,18 @@ "type": "git", | ||
}, | ||
"scripts": { | ||
"postinstall": "node ./lib/postinstall.js" | ||
"exports": { | ||
".": { | ||
"types": "./types/index.d.ts", | ||
"import": "./lib/index.js" | ||
} | ||
}, | ||
"types": "types/index.d.ts", | ||
"author": "CloudCannon", | ||
"license": "MIT", | ||
"dependencies": { | ||
"https-proxy-agent": "^5.0.0", | ||
"proxy-from-env": "^1.1.0" | ||
"optionalDependencies": { | ||
"@pagefind/linux-x64": "1.0.3", | ||
"@pagefind/linux-arm64": "1.0.3", | ||
"@pagefind/darwin-x64": "1.0.3", | ||
"@pagefind/darwin-arm64": "1.0.3", | ||
"@pagefind/windows-x64": "1.0.3" | ||
}, | ||
"overrides": { | ||
"agent-base": "^6.0.2" | ||
}, | ||
"keywords": [ | ||
@@ -37,3 +43,6 @@ "CloudCannon", | ||
}, | ||
"homepage": "https://github.com/CloudCannon/pagefind#readme" | ||
"homepage": "https://github.com/CloudCannon/pagefind#readme", | ||
"devDependencies": { | ||
"@types/node": "^20.4.5" | ||
} | ||
} |
@@ -1,3 +0,50 @@ | ||
# Pagefind | ||
# Pagefind Static Search | ||
The CLI for Pagefind. | ||
Pagefind is a fully static search library that aims to perform well on large sites, while using as little of your users’ bandwidth as possible, and without hosting any infrastructure. | ||
The full documentation on using Pagefind can be found at https://pagefind.app/. | ||
This packages houses a wrapper for running the precompiled Pagefind binary, and also serves as a NodeJS indexing library that can be integrated into existing tools. | ||
## Running Pagefind through NPX | ||
This is the recommended way of running Pagefind on a static site. | ||
```bash | ||
npx pagefind --site "public" | ||
``` | ||
For more details on using the Pagefind binary, see [Installing and running Pagefind](https://pagefind.app/docs/installation/#running-via-npx), and the rest of the Pagefind documentation. | ||
## Using Pagefind as a Node library | ||
This package also provides an interface to the Pagefind binary directly as a package you can import. | ||
```js | ||
import * as pagefind from "pagefind"; | ||
// Create a Pagefind search index to work with | ||
const { index } = await pagefind.createIndex(); | ||
// Index all HTML files in a directory | ||
await index.addDirectory({ | ||
path: "public" | ||
}); | ||
// Add extra content | ||
await index.addCustomRecord({ | ||
url: "/resume.pdf", | ||
content: "Aenean lacinia bibendum nulla sed consectetur", | ||
language: "en", | ||
}); | ||
// Get the index files in-memory | ||
const { files } = await index.getFiles(); | ||
// Or, write the index to disk | ||
await index.writeFiles({ | ||
outputPath: "public/pagefind" | ||
}); | ||
``` | ||
For more details on using Pagefind as a library, see [Indexing content using the NodeJS API](https://pagefind.app/docs/node-api/). |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
36386
23
907
0
51
0
3
2
Yes
5
1
+ Added@pagefind/darwin-arm64@1.0.3(transitive)
+ Added@pagefind/darwin-x64@1.0.3(transitive)
+ Added@pagefind/linux-arm64@1.0.3(transitive)
+ Added@pagefind/linux-x64@1.0.3(transitive)
+ Added@pagefind/windows-x64@1.0.3(transitive)
- Removedhttps-proxy-agent@^5.0.0
- Removedproxy-from-env@^1.1.0
- Removedagent-base@6.0.2(transitive)
- Removeddebug@4.3.7(transitive)
- Removedhttps-proxy-agent@5.0.1(transitive)
- Removedms@2.1.3(transitive)
- Removedproxy-from-env@1.1.0(transitive)