@embedpdf/plugin-search 2.14.4 → 3.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/LICENSE +192 -21
  2. package/dist/index.cjs +363 -2
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +156 -0
  5. package/dist/index.d.ts +156 -1
  6. package/dist/index.js +346 -433
  7. package/dist/index.js.map +1 -1
  8. package/package.json +21 -57
  9. package/dist/lib/actions.d.ts +0 -91
  10. package/dist/lib/index.d.ts +0 -10
  11. package/dist/lib/manifest.d.ts +0 -4
  12. package/dist/lib/reducer.d.ts +0 -6
  13. package/dist/lib/search-plugin.d.ts +0 -32
  14. package/dist/lib/types.d.ts +0 -165
  15. package/dist/preact/adapter.d.ts +0 -5
  16. package/dist/preact/core.d.ts +0 -1
  17. package/dist/preact/index.cjs +0 -2
  18. package/dist/preact/index.cjs.map +0 -1
  19. package/dist/preact/index.d.ts +0 -1
  20. package/dist/preact/index.js +0 -107
  21. package/dist/preact/index.js.map +0 -1
  22. package/dist/react/adapter.d.ts +0 -2
  23. package/dist/react/core.d.ts +0 -1
  24. package/dist/react/index.cjs +0 -2
  25. package/dist/react/index.cjs.map +0 -1
  26. package/dist/react/index.d.ts +0 -1
  27. package/dist/react/index.js +0 -106
  28. package/dist/react/index.js.map +0 -1
  29. package/dist/shared/components/index.d.ts +0 -1
  30. package/dist/shared/components/search-layer.d.ts +0 -11
  31. package/dist/shared/hooks/index.d.ts +0 -1
  32. package/dist/shared/hooks/use-search.d.ts +0 -15
  33. package/dist/shared/index.d.ts +0 -3
  34. package/dist/shared-preact/components/index.d.ts +0 -1
  35. package/dist/shared-preact/components/search-layer.d.ts +0 -11
  36. package/dist/shared-preact/hooks/index.d.ts +0 -1
  37. package/dist/shared-preact/hooks/use-search.d.ts +0 -15
  38. package/dist/shared-preact/index.d.ts +0 -3
  39. package/dist/shared-react/components/index.d.ts +0 -1
  40. package/dist/shared-react/components/search-layer.d.ts +0 -11
  41. package/dist/shared-react/hooks/index.d.ts +0 -1
  42. package/dist/shared-react/hooks/use-search.d.ts +0 -15
  43. package/dist/shared-react/index.d.ts +0 -3
  44. package/dist/svelte/components/SearchLayer.svelte.d.ts +0 -11
  45. package/dist/svelte/components/index.d.ts +0 -1
  46. package/dist/svelte/hooks/index.d.ts +0 -1
  47. package/dist/svelte/hooks/use-search.svelte.d.ts +0 -21
  48. package/dist/svelte/index.cjs +0 -2
  49. package/dist/svelte/index.cjs.map +0 -1
  50. package/dist/svelte/index.d.ts +0 -3
  51. package/dist/svelte/index.js +0 -129
  52. package/dist/svelte/index.js.map +0 -1
  53. package/dist/vue/components/index.d.ts +0 -1
  54. package/dist/vue/components/search-layer.vue.d.ts +0 -13
  55. package/dist/vue/hooks/index.d.ts +0 -1
  56. package/dist/vue/hooks/use-search.d.ts +0 -12
  57. package/dist/vue/index.cjs +0 -2
  58. package/dist/vue/index.cjs.map +0 -1
  59. package/dist/vue/index.d.ts +0 -3
  60. package/dist/vue/index.js +0 -131
  61. package/dist/vue/index.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/search-plugin.ts","../src/lib/manifest.ts","../src/lib/index.ts"],"sourcesContent":["import { Action } from '@embedpdf/core';\nimport { MatchFlag, SearchResult } from '@embedpdf/models';\nimport { SearchDocumentState } from './types';\n\n// Action Types\nexport const INIT_SEARCH_STATE = 'SEARCH/INIT_STATE';\nexport const CLEANUP_SEARCH_STATE = 'SEARCH/CLEANUP_STATE';\nexport const START_SEARCH_SESSION = 'SEARCH/START_SEARCH_SESSION';\nexport const STOP_SEARCH_SESSION = 'SEARCH/STOP_SEARCH_SESSION';\nexport const SET_SEARCH_FLAGS = 'SEARCH/SET_SEARCH_FLAGS';\nexport const SET_SHOW_ALL_RESULTS = 'SEARCH/SET_SHOW_ALL_RESULTS';\nexport const START_SEARCH = 'SEARCH/START_SEARCH';\nexport const SET_SEARCH_RESULTS = 'SEARCH/SET_SEARCH_RESULTS';\nexport const APPEND_SEARCH_RESULTS = 'SEARCH/APPEND_SEARCH_RESULTS';\nexport const SET_ACTIVE_RESULT_INDEX = 'SEARCH/SET_ACTIVE_RESULT_INDEX';\n\n// Action Interfaces\nexport interface InitSearchStateAction extends Action {\n type: typeof INIT_SEARCH_STATE;\n payload: { documentId: string; state: SearchDocumentState };\n}\n\nexport interface CleanupSearchStateAction extends Action {\n type: typeof CLEANUP_SEARCH_STATE;\n payload: string; // documentId\n}\n\nexport interface StartSearchSessionAction extends Action {\n type: typeof START_SEARCH_SESSION;\n payload: { documentId: string };\n}\n\nexport interface StopSearchSessionAction extends Action {\n type: typeof STOP_SEARCH_SESSION;\n payload: { documentId: string };\n}\n\nexport interface SetSearchFlagsAction extends Action {\n type: typeof SET_SEARCH_FLAGS;\n payload: { documentId: string; flags: MatchFlag[] };\n}\n\nexport interface SetShowAllResultsAction extends Action {\n type: typeof SET_SHOW_ALL_RESULTS;\n payload: { documentId: string; showAll: boolean };\n}\n\nexport interface StartSearchAction extends Action {\n type: typeof START_SEARCH;\n payload: { documentId: string; query: string };\n}\n\nexport interface SetSearchResultsAction extends Action {\n type: typeof SET_SEARCH_RESULTS;\n payload: {\n documentId: string;\n results: SearchResult[];\n total: number;\n activeResultIndex: number;\n };\n}\n\nexport interface AppendSearchResultsAction extends Action {\n type: typeof APPEND_SEARCH_RESULTS;\n payload: {\n documentId: string;\n results: SearchResult[];\n };\n}\n\nexport interface SetActiveResultIndexAction extends Action {\n type: typeof SET_ACTIVE_RESULT_INDEX;\n payload: { documentId: string; index: number };\n}\n\n// Union Type for All Actions\nexport type SearchAction =\n | InitSearchStateAction\n | CleanupSearchStateAction\n | StartSearchSessionAction\n | StopSearchSessionAction\n | SetSearchFlagsAction\n | SetShowAllResultsAction\n | StartSearchAction\n | SetSearchResultsAction\n | AppendSearchResultsAction\n | SetActiveResultIndexAction;\n\n// Action Creators\nexport function initSearchState(\n documentId: string,\n state: SearchDocumentState,\n): InitSearchStateAction {\n return { type: INIT_SEARCH_STATE, payload: { documentId, state } };\n}\n\nexport function cleanupSearchState(documentId: string): CleanupSearchStateAction {\n return { type: CLEANUP_SEARCH_STATE, payload: documentId };\n}\n\nexport function startSearchSession(documentId: string): StartSearchSessionAction {\n return { type: START_SEARCH_SESSION, payload: { documentId } };\n}\n\nexport function stopSearchSession(documentId: string): StopSearchSessionAction {\n return { type: STOP_SEARCH_SESSION, payload: { documentId } };\n}\n\nexport function setSearchFlags(documentId: string, flags: MatchFlag[]): SetSearchFlagsAction {\n return { type: SET_SEARCH_FLAGS, payload: { documentId, flags } };\n}\n\nexport function setShowAllResults(documentId: string, showAll: boolean): SetShowAllResultsAction {\n return { type: SET_SHOW_ALL_RESULTS, payload: { documentId, showAll } };\n}\n\nexport function startSearch(documentId: string, query: string): StartSearchAction {\n return { type: START_SEARCH, payload: { documentId, query } };\n}\n\nexport function setSearchResults(\n documentId: string,\n results: SearchResult[],\n total: number,\n activeResultIndex: number,\n): SetSearchResultsAction {\n return { type: SET_SEARCH_RESULTS, payload: { documentId, results, total, activeResultIndex } };\n}\n\nexport function appendSearchResults(\n documentId: string,\n results: SearchResult[],\n): AppendSearchResultsAction {\n return { type: APPEND_SEARCH_RESULTS, payload: { documentId, results } };\n}\n\nexport function setActiveResultIndex(\n documentId: string,\n index: number,\n): SetActiveResultIndexAction {\n return { type: SET_ACTIVE_RESULT_INDEX, payload: { documentId, index } };\n}\n","import { Reducer } from '@embedpdf/core';\nimport { SearchDocumentState, SearchState } from './types';\nimport {\n START_SEARCH_SESSION,\n STOP_SEARCH_SESSION,\n SET_SEARCH_FLAGS,\n SET_SHOW_ALL_RESULTS,\n START_SEARCH,\n SET_SEARCH_RESULTS,\n APPEND_SEARCH_RESULTS,\n SET_ACTIVE_RESULT_INDEX,\n SearchAction,\n INIT_SEARCH_STATE,\n CLEANUP_SEARCH_STATE,\n} from './actions';\nimport { MatchFlag } from '@embedpdf/models';\n\nexport const initialSearchDocumentState: SearchDocumentState = {\n flags: [] as MatchFlag[],\n results: [],\n total: 0,\n activeResultIndex: -1,\n showAllResults: true,\n query: '',\n loading: false,\n active: false,\n};\n\nexport const initialState: SearchState = {\n documents: {},\n};\n\nconst updateDocState = (\n state: SearchState,\n documentId: string,\n newDocState: Partial<SearchDocumentState>,\n): SearchState => {\n const oldDocState = state.documents[documentId] || initialSearchDocumentState;\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...oldDocState,\n ...newDocState,\n },\n },\n };\n};\n\nexport const searchReducer: Reducer<SearchState, SearchAction> = (state = initialState, action) => {\n switch (action.type) {\n case INIT_SEARCH_STATE:\n return {\n ...state,\n documents: {\n ...state.documents,\n [action.payload.documentId]: action.payload.state,\n },\n };\n\n case CLEANUP_SEARCH_STATE: {\n const documentId = action.payload;\n const { [documentId]: removed, ...remaining } = state.documents;\n return {\n ...state,\n documents: remaining,\n };\n }\n\n case START_SEARCH_SESSION:\n return updateDocState(state, action.payload.documentId, { active: true });\n\n case STOP_SEARCH_SESSION:\n return updateDocState(state, action.payload.documentId, {\n results: [],\n total: 0,\n activeResultIndex: -1,\n query: '',\n loading: false,\n active: false,\n });\n\n case SET_SEARCH_FLAGS:\n return updateDocState(state, action.payload.documentId, { flags: action.payload.flags });\n\n case SET_SHOW_ALL_RESULTS:\n return updateDocState(state, action.payload.documentId, {\n showAllResults: action.payload.showAll,\n });\n\n case START_SEARCH:\n return updateDocState(state, action.payload.documentId, {\n loading: true,\n query: action.payload.query,\n // clear old results on new search start\n results: [],\n total: 0,\n activeResultIndex: -1,\n });\n\n case APPEND_SEARCH_RESULTS: {\n const { documentId, results } = action.payload;\n const docState = state.documents[documentId];\n if (!docState) return state;\n\n const newResults = [...docState.results, ...results];\n const firstHitIndex =\n docState.activeResultIndex === -1 && newResults.length > 0 ? 0 : docState.activeResultIndex;\n return updateDocState(state, documentId, {\n results: newResults,\n total: newResults.length, // total-so-far\n activeResultIndex: firstHitIndex,\n // keep loading true until final SET_SEARCH_RESULTS\n loading: true,\n });\n }\n\n case SET_SEARCH_RESULTS: {\n const { documentId, results, total, activeResultIndex } = action.payload;\n return updateDocState(state, documentId, {\n results,\n total,\n activeResultIndex,\n loading: false,\n });\n }\n\n case SET_ACTIVE_RESULT_INDEX:\n return updateDocState(state, action.payload.documentId, {\n activeResultIndex: action.payload.index,\n });\n\n default:\n return state;\n }\n};\n","import { BasePlugin, createBehaviorEmitter, Listener, PluginRegistry } from '@embedpdf/core';\nimport {\n MatchFlag,\n SearchAllPagesResult,\n PdfEngine,\n PdfTask,\n PdfPageSearchProgress,\n PdfTaskHelper,\n PdfErrorCode,\n} from '@embedpdf/models';\nimport {\n SearchPluginConfig,\n SearchCapability,\n SearchState,\n SearchResultState,\n SearchScope,\n SearchResultEvent,\n SearchStartEvent,\n SearchStopEvent,\n ActiveResultChangeEvent,\n SearchResultStateEvent,\n SearchStateEvent,\n SearchDocumentState,\n} from './types';\nimport {\n startSearchSession,\n stopSearchSession,\n setSearchFlags,\n setShowAllResults,\n startSearch,\n setSearchResults,\n setActiveResultIndex,\n appendSearchResults,\n SearchAction,\n initSearchState,\n cleanupSearchState,\n} from './actions';\nimport { initialSearchDocumentState } from './reducer';\n\nexport class SearchPlugin extends BasePlugin<\n SearchPluginConfig,\n SearchCapability,\n SearchState,\n SearchAction\n> {\n static readonly id = 'search' as const;\n\n // Event emitters are now global and include documentId\n private readonly searchStop$ = createBehaviorEmitter<SearchStopEvent>();\n private readonly searchStart$ = createBehaviorEmitter<SearchStartEvent>();\n private readonly searchResult$ = createBehaviorEmitter<SearchResultEvent>();\n private readonly searchActiveResultChange$ = createBehaviorEmitter<ActiveResultChangeEvent>();\n private readonly searchResultState$ = createBehaviorEmitter<SearchResultStateEvent>();\n private readonly searchState$ = createBehaviorEmitter<SearchStateEvent>();\n\n // Keep reference to current running tasks per document\n private currentTask = new Map<string, ReturnType<PdfEngine['searchAllPages']>>();\n private pluginConfig: SearchPluginConfig;\n\n constructor(id: string, registry: PluginRegistry, config: SearchPluginConfig) {\n super(id, registry);\n this.pluginConfig = config;\n // We no longer need to listen to the loader.\n // Document lifecycle is handled by BasePlugin hooks.\n }\n\n protected override onDocumentLoadingStarted(documentId: string): void {\n const initialState = {\n ...initialSearchDocumentState,\n flags: this.pluginConfig.flags || [],\n showAllResults: this.pluginConfig.showAllResults ?? true,\n };\n this.dispatch(initSearchState(documentId, initialState));\n }\n\n protected override onDocumentClosed(documentId: string): void {\n this.stopSearchSession(documentId); // Ensure any running search is stopped\n this.dispatch(cleanupSearchState(documentId));\n this.currentTask.delete(documentId);\n }\n\n async initialize(): Promise<void> {\n // Config is now handled in onDocumentLoadingStarted\n }\n\n override onStoreUpdated(prevState: SearchState, newState: SearchState): void {\n for (const documentId in newState.documents) {\n const prevDocState = prevState.documents[documentId];\n const newDocState = newState.documents[documentId];\n\n if (prevDocState !== newDocState) {\n // Emit per-document state\n this.searchState$.emit({ documentId, state: newDocState });\n\n // Emit reactive result state\n if (\n !prevDocState ||\n prevDocState.results !== newDocState.results ||\n prevDocState.activeResultIndex !== newDocState.activeResultIndex ||\n prevDocState.showAllResults !== newDocState.showAllResults ||\n prevDocState.active !== newDocState.active\n ) {\n this.searchResultState$.emit({\n documentId,\n state: {\n results: newDocState.results,\n activeResultIndex: newDocState.activeResultIndex,\n showAllResults: newDocState.showAllResults,\n active: newDocState.active,\n },\n });\n }\n }\n }\n }\n\n protected buildCapability(): SearchCapability {\n const getDocId = (documentId?: string) => documentId ?? this.getActiveDocumentId();\n const getDocState = (docId?: string) => {\n const id = getDocId(docId);\n const state = this.state.documents[id];\n if (!state) throw new Error(`Search state not found for document ${id}`);\n return state;\n };\n\n return {\n startSearch: (docId) => this.startSearchSession(getDocId(docId)),\n stopSearch: (docId) => this.stopSearchSession(getDocId(docId)),\n searchAllPages: (keyword, docId) => this.searchAllPages(keyword, getDocId(docId)),\n nextResult: (docId) => this.nextResult(getDocId(docId)),\n previousResult: (docId) => this.previousResult(getDocId(docId)),\n goToResult: (index, docId) => this.goToResult(index, getDocId(docId)),\n setShowAllResults: (showAll, docId) =>\n this.dispatch(setShowAllResults(getDocId(docId), showAll)),\n getShowAllResults: (docId) => getDocState(docId).showAllResults,\n getFlags: (docId) => getDocState(docId).flags,\n setFlags: (flags, docId) => this.setFlags(flags, getDocId(docId)),\n getState: (docId) => getDocState(docId),\n forDocument: this.createSearchScope.bind(this),\n onSearchResult: this.searchResult$.on,\n onSearchStart: this.searchStart$.on,\n onSearchStop: this.searchStop$.on,\n onActiveResultChange: this.searchActiveResultChange$.on,\n onSearchResultStateChange: this.searchResultState$.on,\n onStateChange: this.searchState$.on,\n };\n }\n\n private createSearchScope(documentId: string): SearchScope {\n const getDocState = () => {\n const state = this.state.documents[documentId];\n if (!state) throw new Error(`Search state not found for document ${documentId}`);\n return state;\n };\n\n return {\n startSearch: () => this.startSearchSession(documentId),\n stopSearch: () => this.stopSearchSession(documentId),\n searchAllPages: (keyword) => this.searchAllPages(keyword, documentId),\n nextResult: () => this.nextResult(documentId),\n previousResult: () => this.previousResult(documentId),\n goToResult: (index) => this.goToResult(index, documentId),\n setShowAllResults: (showAll) => this.dispatch(setShowAllResults(documentId, showAll)),\n getShowAllResults: () => getDocState().showAllResults,\n getFlags: () => getDocState().flags,\n setFlags: (flags) => this.setFlags(flags, documentId),\n getState: getDocState,\n onSearchResult: (listener: Listener<SearchAllPagesResult>) =>\n this.searchResult$.on((event) => {\n if (event.documentId === documentId) listener(event.results);\n }),\n onSearchStart: (listener: Listener<void>) =>\n this.searchStart$.on((event) => {\n if (event.documentId === documentId) listener();\n }),\n onSearchStop: (listener: Listener<void>) =>\n this.searchStop$.on((event) => {\n if (event.documentId === documentId) listener();\n }),\n onActiveResultChange: (listener: Listener<number>) =>\n this.searchActiveResultChange$.on((event) => {\n if (event.documentId === documentId) listener(event.index);\n }),\n onSearchResultStateChange: (listener: Listener<SearchResultState>) =>\n this.searchResultState$.on((event) => {\n if (event.documentId === documentId) listener(event.state);\n }),\n onStateChange: (listener: Listener<SearchDocumentState>) =>\n this.searchState$.on((event) => {\n if (event.documentId === documentId) listener(event.state);\n }),\n };\n }\n\n private setFlags(flags: MatchFlag[], documentId: string): void {\n this.dispatch(setSearchFlags(documentId, flags));\n const docState = this.state.documents[documentId];\n if (docState?.active) {\n this.searchAllPages(docState.query, documentId, true);\n }\n }\n\n private notifySearchStart(documentId: string): void {\n this.searchStart$.emit({ documentId });\n }\n\n private notifySearchStop(documentId: string): void {\n this.searchStop$.emit({ documentId });\n }\n\n private notifyActiveResultChange(documentId: string, index: number): void {\n this.searchActiveResultChange$.emit({ documentId, index });\n }\n\n private startSearchSession(documentId: string): void {\n const coreDoc = this.getCoreDocument(documentId);\n if (!coreDoc) return;\n this.dispatch(startSearchSession(documentId));\n this.notifySearchStart(documentId);\n }\n\n private stopSearchSession(documentId: string): void {\n const docState = this.state.documents[documentId];\n if (!docState?.active) return;\n\n const task = this.currentTask.get(documentId);\n if (task) {\n try {\n task.abort?.({ code: PdfErrorCode.Cancelled, message: 'search stopped' });\n } catch {}\n this.currentTask.delete(documentId);\n }\n\n this.dispatch(stopSearchSession(documentId));\n this.notifySearchStop(documentId);\n }\n\n private searchAllPages(\n keyword: string,\n documentId: string,\n force: boolean = false,\n ): PdfTask<SearchAllPagesResult, PdfPageSearchProgress> {\n const docState = this.state.documents[documentId];\n if (!docState) {\n return PdfTaskHelper.reject({\n code: PdfErrorCode.NotFound,\n message: 'Search state not initialized',\n });\n }\n const coreDoc = this.getCoreDocument(documentId);\n if (!coreDoc?.document) {\n return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: 'Document not loaded' });\n }\n\n const trimmedKeyword = keyword.trim();\n\n if (docState.query === trimmedKeyword && !force) {\n return PdfTaskHelper.resolve<SearchAllPagesResult, PdfPageSearchProgress>({\n results: docState.results,\n total: docState.total,\n });\n }\n\n // stop previous task if still running\n const oldTask = this.currentTask.get(documentId);\n if (oldTask) {\n try {\n oldTask.abort?.({ code: PdfErrorCode.Cancelled, message: 'new search' });\n } catch {}\n this.currentTask.delete(documentId);\n }\n\n this.dispatch(startSearch(documentId, trimmedKeyword));\n\n if (!trimmedKeyword) {\n this.dispatch(setSearchResults(documentId, [], 0, -1));\n return PdfTaskHelper.resolve<SearchAllPagesResult, PdfPageSearchProgress>({\n results: [],\n total: 0,\n });\n }\n\n if (!docState.active) {\n this.startSearchSession(documentId);\n }\n\n const task = this.engine.searchAllPages(coreDoc.document, trimmedKeyword, {\n flags: docState.flags,\n });\n this.currentTask.set(documentId, task);\n\n task.onProgress((p) => {\n if (p?.results?.length) {\n // Check if the task is still the current one before dispatching\n if (this.currentTask.get(documentId) === task) {\n this.dispatch(appendSearchResults(documentId, p.results));\n // set first active result as soon as we have something\n if (this.state.documents[documentId].activeResultIndex === -1) {\n this.dispatch(setActiveResultIndex(documentId, 0));\n this.notifyActiveResultChange(documentId, 0);\n }\n }\n }\n });\n\n task.wait(\n (results) => {\n this.currentTask.delete(documentId);\n const activeResultIndex = results.total > 0 ? 0 : -1;\n this.dispatch(\n setSearchResults(documentId, results.results, results.total, activeResultIndex),\n );\n this.searchResult$.emit({ documentId, results });\n if (results.total > 0) {\n this.notifyActiveResultChange(documentId, 0);\n }\n },\n (error) => {\n // Only clear results if the error wasn't an abort\n if (error?.reason?.code !== PdfErrorCode.Cancelled) {\n console.error('Error during search:', error);\n this.dispatch(setSearchResults(documentId, [], 0, -1));\n }\n this.currentTask.delete(documentId);\n },\n );\n\n return task;\n }\n\n private nextResult(documentId: string): number {\n const docState = this.state.documents[documentId];\n if (!docState || docState.results.length === 0) return -1;\n const nextIndex =\n docState.activeResultIndex >= docState.results.length - 1\n ? 0\n : docState.activeResultIndex + 1;\n return this.goToResult(nextIndex, documentId);\n }\n\n private previousResult(documentId: string): number {\n const docState = this.state.documents[documentId];\n if (!docState || docState.results.length === 0) return -1;\n const prevIndex =\n docState.activeResultIndex <= 0\n ? docState.results.length - 1\n : docState.activeResultIndex - 1;\n return this.goToResult(prevIndex, documentId);\n }\n\n private goToResult(index: number, documentId: string): number {\n const docState = this.state.documents[documentId];\n if (\n !docState ||\n docState.results.length === 0 ||\n index < 0 ||\n index >= docState.results.length\n ) {\n return -1;\n }\n this.dispatch(setActiveResultIndex(documentId, index));\n this.notifyActiveResultChange(documentId, index);\n return index;\n }\n\n async destroy(): Promise<void> {\n for (const documentId of Object.keys(this.state.documents)) {\n this.stopSearchSession(documentId);\n }\n this.searchResult$.clear();\n this.searchStart$.clear();\n this.searchStop$.clear();\n this.searchActiveResultChange$.clear();\n this.searchResultState$.clear();\n this.searchState$.clear();\n super.destroy();\n }\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { SearchPluginConfig } from './types';\n\nexport const SEARCH_PLUGIN_ID = 'search';\n\nexport const manifest: PluginManifest<SearchPluginConfig> = {\n id: SEARCH_PLUGIN_ID,\n name: 'Search Plugin',\n version: '1.0.0',\n provides: ['search'],\n requires: [],\n optional: [],\n defaultConfig: {\n flags: [],\n },\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { SearchPlugin } from './search-plugin';\nimport { manifest, SEARCH_PLUGIN_ID } from './manifest';\nimport { SearchPluginConfig, SearchState } from './types';\nimport { searchReducer, initialState, initialSearchDocumentState } from './reducer';\nimport { SearchAction } from './actions';\n\nexport const SearchPluginPackage: PluginPackage<\n SearchPlugin,\n SearchPluginConfig,\n SearchState,\n SearchAction\n> = {\n manifest,\n create: (registry, config) => new SearchPlugin(SEARCH_PLUGIN_ID, registry, config),\n reducer: searchReducer,\n initialState,\n};\n\nexport * from './search-plugin';\nexport * from './types';\nexport * from './manifest';\nexport { initialState, initialSearchDocumentState };\n"],"names":["INIT_SEARCH_STATE","CLEANUP_SEARCH_STATE","START_SEARCH_SESSION","STOP_SEARCH_SESSION","SET_SEARCH_FLAGS","SET_SHOW_ALL_RESULTS","START_SEARCH","SET_SEARCH_RESULTS","APPEND_SEARCH_RESULTS","SET_ACTIVE_RESULT_INDEX","setShowAllResults","documentId","showAll","type","payload","setSearchResults","results","total","activeResultIndex","setActiveResultIndex","index","initialSearchDocumentState","flags","showAllResults","query","loading","active","initialState","documents","updateDocState","state","newDocState","oldDocState","_SearchPlugin","BasePlugin","constructor","id","registry","config","super","this","searchStop$","createBehaviorEmitter","searchStart$","searchResult$","searchActiveResultChange$","searchResultState$","searchState$","currentTask","Map","pluginConfig","onDocumentLoadingStarted","dispatch","initSearchState","onDocumentClosed","stopSearchSession","cleanupSearchState","delete","initialize","onStoreUpdated","prevState","newState","prevDocState","emit","buildCapability","getDocId","getActiveDocumentId","getDocState","docId","Error","startSearch","startSearchSession","stopSearch","searchAllPages","keyword","nextResult","previousResult","goToResult","getShowAllResults","getFlags","setFlags","getState","forDocument","createSearchScope","bind","onSearchResult","on","onSearchStart","onSearchStop","onActiveResultChange","onSearchResultStateChange","onStateChange","listener","event","setSearchFlags","docState","notifySearchStart","notifySearchStop","notifyActiveResultChange","getCoreDocument","task","get","_a","abort","code","PdfErrorCode","Cancelled","message","force","PdfTaskHelper","reject","NotFound","coreDoc","document","trimmedKeyword","trim","resolve","oldTask","engine","set","onProgress","p","length","appendSearchResults","wait","error","reason","console","nextIndex","prevIndex","destroy","Object","keys","clear","SearchPlugin","SEARCH_PLUGIN_ID","manifest","name","version","provides","requires","optional","defaultConfig","SearchPluginPackage","create","reducer","action","removed","remaining","newResults","firstHitIndex"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["EngineError","EngineErrorCode","StageToken","StageToken"],"sources":["../src/capability.ts","../src/types.ts","../src/effects.ts","../src/reducer.ts","../src/search.plugin.ts"],"sourcesContent":["import type { PageObjectNumber, PluginContext } from '@embedpdf/core';\nimport {\n applyRect,\n boundsOfRects,\n pageGeometry,\n type Rect,\n type RectIn,\n} from '@embedpdf/core-geometry';\nimport { StageToken } from '@embedpdf/plugin-stage';\nimport { EngineError, EngineErrorCode } from '@embedpdf/engine-core/runtime';\nimport type {\n PdfRect,\n SearchMatch,\n SearchMode,\n SearchQuery,\n SearchSlice,\n} from '@embedpdf/engine-core/runtime';\n\nimport type {\n SearchAction,\n SearchCapability,\n SearchHit,\n SearchPluginConfig,\n SearchRevealOptions,\n SearchState,\n} from './types';\n\nconst EMPTY: SearchHit[] = [];\n\n/** The browser find-bar feel: hit at the top-middle, no zoom change. */\nconst DEFAULT_REVEAL: SearchRevealOptions = { anchor: { y: 0.35 }, behavior: 'smooth' };\n\n/** Local engines reject a denied scope before the worker; cloud maps 403. */\nconst isPermissionDenied = (err: unknown): boolean =>\n (err instanceof Error && err.name === 'PermissionDenied') ||\n EngineError.is(err, EngineErrorCode.Forbidden);\n\n/**\n * The search capability: a client-driven cursor loop over the engine's\n * budgeted slices. One generation counter arbitrates: a new `search()` (or\n * `clear()`, or a document mutation via `rerun()`) supersedes the running\n * loop, which aborts its in-flight slice and stops dispatching.\n *\n * Rect conversion happens HERE, once per slice: the engine's PDF-space\n * line rects → content space through the same page geometry the selection\n * plugin uses, so search highlights and selection highlights are pixel-twins.\n *\n * Stage integration is optional and additive: with a Stage present the scan\n * starts at the current page (viewport-first — the hits the user is looking\n * at arrive in the first slice) and `next()`/`prev()`/`goTo()` reveal the\n * hit's page. Without one, navigation still works; the host scrolls.\n */\nexport function createSearchCapability(\n ctx: PluginContext<SearchState, SearchAction>,\n config: SearchPluginConfig = {},\n): SearchCapability {\n let generation = 0;\n let inflight: { abort(reason?: unknown): void } | null = null;\n\n const toContent = (m: ReturnType<typeof pageGeometry>['pdfToContent'], b: PdfRect): Rect =>\n applyRect(\n m as never,\n {\n x: b.left,\n y: b.bottom,\n width: b.right - b.left,\n height: b.top - b.bottom,\n } as RectIn<'pdf'>,\n ) as Rect;\n\n interface PageConverter {\n pageIndex: number;\n toRect: (b: PdfRect) => Rect;\n }\n\n function hitsFromSlice(slice: SearchSlice): SearchHit[] {\n // zoom = 1: content space is scale-free; the layer applies the page\n // transform at render time (the selection idiom).\n const converters = new Map<PageObjectNumber, PageConverter | null>();\n const converterFor = (pon: PageObjectNumber): PageConverter | null => {\n let conv = converters.get(pon);\n if (conv !== undefined) return conv;\n const layout = ctx.document()?.pages.find((p) => p.pageObjectNumber === pon);\n if (!layout) {\n conv = null; // page vanished mid-search (delete); drop its hits\n } else {\n const { pdfToContent } = pageGeometry(\n { crop: layout.boxes.crop, rotation: layout.rotation, userUnit: layout.userUnit },\n 1,\n );\n conv = { pageIndex: layout.index, toRect: (b) => toContent(pdfToContent, b) };\n }\n converters.set(pon, conv);\n return conv;\n };\n\n const hits: SearchHit[] = [];\n for (const match of slice.matches) {\n const conv = converterFor(match.pageObjectNumber);\n if (!conv) continue;\n hits.push({\n pon: match.pageObjectNumber,\n pageIndex: conv.pageIndex,\n charStart: match.charStart,\n charCount: match.charCount,\n rects: match.rects.map(conv.toRect),\n ...(match.snippet ? { snippet: match.snippet } : {}),\n });\n }\n return hits;\n }\n\n /** How a collect() consumer observes the loop — the session dispatches\n * into state, findAll accumulates locally. */\n interface CollectSink {\n /** Called before the first slice AND again on a stale-cursor restart —\n * reset any accumulation. */\n onStart: () => void;\n onSlice: (hits: SearchHit[], scanned: number, total: number) => void;\n /** Superseded / aborted — the loop stops without completing. */\n isCancelled: () => boolean;\n setInflight: (pending: { abort(reason?: unknown): void } | null) => void;\n }\n\n /**\n * THE MECHANISM — one cursor loop over the engine's budgeted slices,\n * shared by the session (`search`) and the session-free service\n * (`findAll`): permission fallback ('full' → 'rects' when snippets are\n * denied, unless the caller pinned a mode), restart-once on a stale\n * cursor, rect conversion per slice. Resolves true on exhaustion, false\n * when cancelled; throws on error.\n */\n async function collect(\n query: SearchQuery,\n opts: { startPage?: PageObjectNumber; mode?: SearchMode },\n sink: CollectSink,\n ): Promise<boolean> {\n const doc = ctx.doc;\n if (!doc) return false;\n\n sink.onStart();\n\n let mode: SearchMode = opts.mode ?? 'full';\n const modePinned = opts.mode !== undefined;\n let cursor: string | undefined;\n let restarted = false;\n for (;;) {\n let slice: SearchSlice;\n try {\n const request = {\n query,\n mode,\n ...(cursor !== undefined\n ? { cursor }\n : opts.startPage !== undefined\n ? { startPage: opts.startPage }\n : {}),\n };\n const pending = doc.search.query(request);\n sink.setInflight(pending);\n slice = await pending;\n } catch (err) {\n if (sink.isCancelled()) return false; // superseded — the abort was ours\n // Snippets denied (no doc.text.copy)? Degrade to rect-only matches\n // instead of failing the whole search — find still works.\n if (!modePinned && mode === 'full' && cursor === undefined && isPermissionDenied(err)) {\n mode = 'rects';\n continue;\n }\n // A stale cursor rejects with InvalidArg — the document changed\n // under the loop, or the engine's session was recycled. Position\n // is lost, the query isn't: restart once from scratch.\n if (cursor !== undefined && !restarted && EngineError.is(err, EngineErrorCode.InvalidArg)) {\n restarted = true;\n cursor = undefined;\n sink.onStart();\n continue;\n }\n throw err;\n }\n if (sink.isCancelled()) return false;\n sink.onSlice(hitsFromSlice(slice), slice.scannedPages, slice.totalPages);\n if (slice.nextCursor === null) {\n sink.setInflight(null);\n return true;\n }\n cursor = slice.nextCursor;\n }\n }\n\n /** THE SESSION — collect() with state as the sink, generation-guarded. */\n async function runSession(query: SearchQuery, startPage?: PageObjectNumber): Promise<void> {\n const gen = ++generation;\n inflight?.abort('superseded');\n inflight = null;\n\n if (!ctx.doc) {\n ctx.dispatch({ type: 'CLEAR' });\n return;\n }\n\n // Viewport-first: begin scanning where the user is looking.\n if (startPage === undefined) {\n const stage = ctx.tryGet(StageToken);\n if (stage) startPage = ctx.document()?.pages[stage.currentPage()]?.pageObjectNumber;\n }\n\n try {\n const complete = await collect(\n query,\n { startPage },\n {\n onStart: () => ctx.dispatch({ type: 'START', query }),\n onSlice: (hits, scanned, total) => ctx.dispatch({ type: 'APPEND', hits, scanned, total }),\n isCancelled: () => gen !== generation,\n setInflight: (pending) => {\n if (gen === generation) inflight = pending;\n },\n },\n );\n if (complete && gen === generation) ctx.dispatch({ type: 'COMPLETE' });\n } catch (err) {\n if (gen !== generation) return;\n ctx.dispatch({ type: 'ERROR', message: err instanceof Error ? err.message : String(err) });\n }\n }\n\n function goTo(index: number, reveal?: SearchRevealOptions): SearchHit | null {\n const { hits } = ctx.getState();\n if (hits.length === 0) return null;\n const wrapped = ((index % hits.length) + hits.length) % hits.length;\n ctx.dispatch({ type: 'SET_ACTIVE', index: wrapped });\n const hit = hits[wrapped];\n // Positioned reveal: the HIT (not just its page) arrives at the anchor —\n // per-call override > plugin config > find-bar default. Zoom never changes.\n const arrival = { ...DEFAULT_REVEAL, ...config.reveal, ...reveal };\n ctx.tryGet(StageToken)?.reveal(hit.pageIndex, {\n rect: boundsOfRects(hit.rects) ?? undefined,\n anchor: arrival.anchor,\n behavior: arrival.behavior,\n });\n return hit;\n }\n\n const clear = () => {\n generation++;\n inflight?.abort('cleared');\n inflight = null;\n ctx.dispatch({ type: 'CLEAR' });\n };\n\n return {\n // An empty text is \"stop searching\", not a query — identical to clear().\n search: (query, exec) =>\n query.text.length === 0 ? clear() : void runSession(query, exec?.startPage),\n\n // Replay the stored query verbatim; the rescan starts viewport-first.\n rerun: () => {\n const { query, status } = ctx.getState();\n if (query && status !== 'idle') void runSession(query);\n },\n\n clear,\n\n next: () => goTo(ctx.getState().activeIndex + 1),\n prev: () => goTo(ctx.getState().activeIndex - 1),\n goTo,\n\n query: () => ctx.getState().query,\n\n findAll: async (query, opts = {}) => {\n if (!ctx.doc) return [];\n const all: SearchHit[] = [];\n const signal = opts.signal;\n // Independent lifecycle: its own abort handle, never the session's\n // generation counter — a findAll can neither supersede the user's\n // visible search nor be superseded by it.\n let pending: { abort(reason?: unknown): void } | null = null;\n const onAbort = () => pending?.abort(signal?.reason);\n signal?.addEventListener('abort', onAbort, { once: true });\n try {\n await collect(\n query,\n { mode: opts.mode },\n {\n onStart: () => {\n all.length = 0;\n },\n onSlice: (hits) => all.push(...hits),\n isCancelled: () => signal?.aborted ?? false,\n setInflight: (p) => {\n pending = p;\n },\n },\n );\n if (signal?.aborted) throw signal.reason ?? new Error('findAll aborted');\n return all;\n } finally {\n signal?.removeEventListener('abort', onAbort);\n }\n },\n\n status: () => ctx.getState().status,\n hits: () => ctx.getState().hits,\n hitCount: () => ctx.getState().hits.length,\n activeIndex: () => ctx.getState().activeIndex,\n activeHit: () => {\n const { hits, activeIndex } = ctx.getState();\n return activeIndex >= 0 && activeIndex < hits.length ? hits[activeIndex] : null;\n },\n hitsForPage: (pon) => {\n const { hits, hitsByPage } = ctx.getState();\n const indices = hitsByPage[pon];\n return indices?.length ? indices.map((i) => hits[i]) : EMPTY;\n },\n progress: () => ctx.getState().progress,\n errorMessage: () => ctx.getState().error,\n };\n}\n","import { createCapabilityToken, type PageObjectNumber } from '@embedpdf/core';\nimport type { Rect } from '@embedpdf/core-geometry';\nimport type { RevealAnchor, ScrollBehaviorKind } from '@embedpdf/plugin-stage';\nimport type { SearchMode, SearchQuery, SearchSnippet } from '@embedpdf/engine-core/runtime';\n\n/**\n * One match, viewer-shaped: the engine's PDF-space line rects converted to\n * CONTENT space (y-down — the same space selection rects live in), plus the\n * page's display index so navigation can `reveal()` without a lookup.\n * `charStart`/`charCount` keep the engine's text-page offsets, so a hit can\n * later seed a selection or a highlight annotation without re-searching.\n */\nexport interface SearchHit {\n pon: PageObjectNumber;\n pageIndex: number;\n charStart: number;\n charCount: number;\n rects: Rect[];\n snippet?: SearchSnippet;\n}\n\n/**\n * `searching` means the slice loop is still walking pages — results are\n * usable the moment they appear (matches stream in viewport-first order).\n */\nexport type SearchStatus = 'idle' | 'searching' | 'complete' | 'error';\n\n/**\n * Execution options for the session `search()` — HOW the scan runs, never\n * part of what the query MEANS (which is why they're not on `SearchQuery`\n * and are never stored or restored into a search box).\n */\nexport interface SearchExecOptions {\n /** Scan origin override. Defaults to the Stage's current page (viewport-first). */\n startPage?: PageObjectNumber;\n}\n\n/** Options for the session-free `findAll()` service. */\nexport interface SearchFindAllOptions {\n /** Abort the scan; the returned promise rejects with `signal.reason`. */\n signal?: AbortSignal;\n /**\n * Pin the slice mode. Default: `'full'` with automatic `'rects'`\n * fallback when snippets are denied — pass `'rects'` when you only need\n * geometry (e.g. redact-by-term) to skip snippet extraction entirely.\n */\n mode?: SearchMode;\n}\n\nexport interface SearchState {\n /**\n * The query in flight/completed, null when idle/cleared — THE stored\n * form of the search intent, the same flat `SearchQuery` the engine\n * matches on, the wire caches by, and a search box renders. Survives\n * any search UI unmounting (results are document-scoped; so is this).\n */\n query: SearchQuery | null;\n status: SearchStatus;\n hits: SearchHit[];\n /** pon → indices into `hits` — the per-page layer's read model. */\n hitsByPage: Record<number, number[]>;\n /** Index into `hits`, -1 = none. */\n activeIndex: number;\n progress: { scanned: number; total: number };\n error: string | null;\n}\n\nexport type SearchAction =\n | { type: 'START'; query: SearchQuery }\n | { type: 'APPEND'; hits: SearchHit[]; scanned: number; total: number }\n | { type: 'COMPLETE' }\n | { type: 'ERROR'; message: string }\n | { type: 'SET_ACTIVE'; index: number }\n | { type: 'CLEAR' };\n\n/**\n * How hit navigation arrives (forwarded to the Stage's positioned reveal).\n * The default is the browser find-bar feel: the hit lands at the top-middle\n * of the viewport (`anchor: { y: 0.35 }`), horizontal only moves when the\n * hit is off-screen, zoom never changes, smooth tween.\n */\nexport interface SearchRevealOptions {\n anchor?: RevealAnchor;\n behavior?: ScrollBehaviorKind;\n}\n\nexport interface SearchPluginConfig {\n /** Arrival defaults for `next()`/`prev()`/`goTo()`. */\n reveal?: SearchRevealOptions;\n}\n\n/**\n * The search plugin is a find SERVICE plus one user-visible search SESSION\n * per document. `findAll` is the service; `search` is the session; the\n * sidebar, the highlights layer, and next/prev render the session.\n */\nexport interface SearchCapability {\n // ── the session: THE user-visible find, one per document ────────────────\n /**\n * Start a new search (supersedes and aborts any running one). Results\n * stream into state slice by slice; the first hit becomes active but the\n * camera does NOT move until `next()`/`prev()`/`goTo()`. An empty\n * `query.text` is \"stop searching\" — identical to `clear()`.\n */\n search(query: SearchQuery, exec?: SearchExecOptions): void;\n /** Re-run the current query from scratch (used after document mutations). */\n rerun(): void;\n clear(): void;\n\n /** Advance to the next/previous hit (wraps) and reveal it (see {@link SearchRevealOptions}). */\n next(): SearchHit | null;\n prev(): SearchHit | null;\n /** Jump to a specific hit index and reveal it; `reveal` overrides the plugin defaults. */\n goTo(index: number, reveal?: SearchRevealOptions): SearchHit | null;\n\n /** The session's query — what a search box renders. Null when idle. */\n query(): SearchQuery | null;\n status(): SearchStatus;\n hits(): SearchHit[];\n hitCount(): number;\n activeIndex(): number;\n activeHit(): SearchHit | null;\n /** Hits on one page — the layer's input. Element identity is stable. */\n hitsForPage(pon: PageObjectNumber): SearchHit[];\n progress(): { scanned: number; total: number };\n errorMessage(): string | null;\n\n // ── the mechanism: session-free find service ─────────────────────────────\n /**\n * Run a query to completion and return every hit. Touches NO state — no\n * sidebar, no highlights, no camera, no activeIndex; the user's visible\n * search is never superseded. The primitive other features build on\n * (redact-by-term, link detection, occurrence badges). Scans in natural\n * page order; concurrent calls are independent.\n */\n findAll(query: SearchQuery, opts?: SearchFindAllOptions): Promise<SearchHit[]>;\n}\n\nexport const SearchToken = createCapabilityToken<SearchCapability>('search');\n","/**\n * Keeps results honest across document mutations. Every confirmed\n * mutation (own or remote) bumps the engine's mutation sequence, which\n * invalidates search cursors AND can change what's findable (redaction,\n * page delete, import). The correct reaction is always the same: re-run\n * the current query from scratch. Reruns are coalesced — a burst of\n * events (multi-part mutation, SSE catch-up) triggers one rescan.\n */\nimport type { EffectContext } from '@embedpdf/core';\n\nimport { SearchToken } from './types';\nimport type { SearchAction, SearchState } from './types';\n\nconst RERUN_DELAY_MS = 250;\n\nexport function registerSearchEffects(ctx: EffectContext<SearchState, SearchAction>): void {\n const doc = ctx.doc;\n if (!doc) return;\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n const unsubscribe = doc.events.subscribe(() => {\n if (ctx.getState().status === 'idle') return;\n if (timer !== null) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n ctx.get(SearchToken).rerun();\n }, RERUN_DELAY_MS);\n });\n\n ctx.cleanup(() => {\n if (timer !== null) clearTimeout(timer);\n unsubscribe();\n });\n}\n","import type { SearchAction, SearchState } from './types';\n\nexport const initialSearchState = (): SearchState => ({\n query: null,\n status: 'idle',\n hits: [],\n hitsByPage: {},\n activeIndex: -1,\n progress: { scanned: 0, total: 0 },\n error: null,\n});\n\nexport const searchReducer = (state: SearchState, action: SearchAction): SearchState => {\n switch (action.type) {\n case 'START':\n return { ...initialSearchState(), query: action.query, status: 'searching' };\n case 'APPEND': {\n if (action.hits.length === 0) {\n return { ...state, progress: { scanned: action.scanned, total: action.total } };\n }\n const hits = state.hits.concat(action.hits);\n const hitsByPage = { ...state.hitsByPage };\n for (let i = state.hits.length; i < hits.length; i++) {\n const pon = hits[i].pon;\n hitsByPage[pon] = (hitsByPage[pon] ?? []).concat(i);\n }\n return {\n ...state,\n hits,\n hitsByPage,\n // The first hit becomes active (so \"1/N\" reads right) — navigation,\n // not the stream, moves the camera.\n activeIndex: state.activeIndex === -1 ? 0 : state.activeIndex,\n progress: { scanned: action.scanned, total: action.total },\n };\n }\n case 'COMPLETE':\n return { ...state, status: 'complete' };\n case 'ERROR':\n return { ...state, status: 'error', error: action.message };\n case 'SET_ACTIVE':\n return { ...state, activeIndex: action.index };\n case 'CLEAR':\n return initialSearchState();\n default:\n return state;\n }\n};\n","import { definePlugin } from '@embedpdf/core';\nimport { StageToken } from '@embedpdf/plugin-stage';\n\nimport { createSearchCapability } from './capability';\nimport { registerSearchEffects } from './effects';\nimport { initialSearchState, searchReducer } from './reducer';\nimport { SearchToken } from './types';\nimport type { SearchAction, SearchCapability, SearchPluginConfig, SearchState } from './types';\n\n/**\n * Document text search over `doc.search` — the engine's budgeted,\n * cursor-resumable slices. Document-scoped; no pointer handling, so it\n * needs no interaction hub. The Stage is optional: when present, scans\n * start at the current page (viewport-first) and hit navigation reveals\n * the hit's page; without it the host owns scrolling.\n */\nexport const searchPlugin = (config?: SearchPluginConfig) =>\n definePlugin<SearchState, SearchAction, SearchCapability>({\n id: 'search',\n token: SearchToken,\n scope: 'document',\n optional: [StageToken],\n initialState: initialSearchState,\n reduce: searchReducer,\n capability: (ctx) => createSearchCapability(ctx, config),\n effects: registerSearchEffects,\n });\n"],"mappings":"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"}
@@ -0,0 +1,156 @@
1
+ import { PageObjectNumber } from "@embedpdf/core";
2
+ import { Rect } from "@embedpdf/core-geometry";
3
+ import { RevealAnchor, ScrollBehaviorKind } from "@embedpdf/plugin-stage";
4
+ import { SearchMode, SearchQuery, SearchQuery as SearchQuery$1, SearchQueryIssue, SearchQueryValidation, SearchRegexValidation, SearchSnippet, SearchSnippet as SearchSnippet$1, validateSearchQuery, validateSearchRegex } from "@embedpdf/engine-core/runtime";
5
+ //#region src/types.d.ts
6
+ /**
7
+ * One match, viewer-shaped: the engine's PDF-space line rects converted to
8
+ * CONTENT space (y-down — the same space selection rects live in), plus the
9
+ * page's display index so navigation can `reveal()` without a lookup.
10
+ * `charStart`/`charCount` keep the engine's text-page offsets, so a hit can
11
+ * later seed a selection or a highlight annotation without re-searching.
12
+ */
13
+ interface SearchHit {
14
+ pon: PageObjectNumber;
15
+ pageIndex: number;
16
+ charStart: number;
17
+ charCount: number;
18
+ rects: Rect[];
19
+ snippet?: SearchSnippet$1;
20
+ }
21
+ /**
22
+ * `searching` means the slice loop is still walking pages — results are
23
+ * usable the moment they appear (matches stream in viewport-first order).
24
+ */
25
+ type SearchStatus = 'idle' | 'searching' | 'complete' | 'error';
26
+ /**
27
+ * Execution options for the session `search()` — HOW the scan runs, never
28
+ * part of what the query MEANS (which is why they're not on `SearchQuery`
29
+ * and are never stored or restored into a search box).
30
+ */
31
+ interface SearchExecOptions {
32
+ /** Scan origin override. Defaults to the Stage's current page (viewport-first). */
33
+ startPage?: PageObjectNumber;
34
+ }
35
+ /** Options for the session-free `findAll()` service. */
36
+ interface SearchFindAllOptions {
37
+ /** Abort the scan; the returned promise rejects with `signal.reason`. */
38
+ signal?: AbortSignal;
39
+ /**
40
+ * Pin the slice mode. Default: `'full'` with automatic `'rects'`
41
+ * fallback when snippets are denied — pass `'rects'` when you only need
42
+ * geometry (e.g. redact-by-term) to skip snippet extraction entirely.
43
+ */
44
+ mode?: SearchMode;
45
+ }
46
+ interface SearchState {
47
+ /**
48
+ * The query in flight/completed, null when idle/cleared — THE stored
49
+ * form of the search intent, the same flat `SearchQuery` the engine
50
+ * matches on, the wire caches by, and a search box renders. Survives
51
+ * any search UI unmounting (results are document-scoped; so is this).
52
+ */
53
+ query: SearchQuery$1 | null;
54
+ status: SearchStatus;
55
+ hits: SearchHit[];
56
+ /** pon → indices into `hits` — the per-page layer's read model. */
57
+ hitsByPage: Record<number, number[]>;
58
+ /** Index into `hits`, -1 = none. */
59
+ activeIndex: number;
60
+ progress: {
61
+ scanned: number;
62
+ total: number;
63
+ };
64
+ error: string | null;
65
+ }
66
+ type SearchAction = {
67
+ type: 'START';
68
+ query: SearchQuery$1;
69
+ } | {
70
+ type: 'APPEND';
71
+ hits: SearchHit[];
72
+ scanned: number;
73
+ total: number;
74
+ } | {
75
+ type: 'COMPLETE';
76
+ } | {
77
+ type: 'ERROR';
78
+ message: string;
79
+ } | {
80
+ type: 'SET_ACTIVE';
81
+ index: number;
82
+ } | {
83
+ type: 'CLEAR';
84
+ };
85
+ /**
86
+ * How hit navigation arrives (forwarded to the Stage's positioned reveal).
87
+ * The default is the browser find-bar feel: the hit lands at the top-middle
88
+ * of the viewport (`anchor: { y: 0.35 }`), horizontal only moves when the
89
+ * hit is off-screen, zoom never changes, smooth tween.
90
+ */
91
+ interface SearchRevealOptions {
92
+ anchor?: RevealAnchor;
93
+ behavior?: ScrollBehaviorKind;
94
+ }
95
+ interface SearchPluginConfig {
96
+ /** Arrival defaults for `next()`/`prev()`/`goTo()`. */
97
+ reveal?: SearchRevealOptions;
98
+ }
99
+ /**
100
+ * The search plugin is a find SERVICE plus one user-visible search SESSION
101
+ * per document. `findAll` is the service; `search` is the session; the
102
+ * sidebar, the highlights layer, and next/prev render the session.
103
+ */
104
+ interface SearchCapability {
105
+ /**
106
+ * Start a new search (supersedes and aborts any running one). Results
107
+ * stream into state slice by slice; the first hit becomes active but the
108
+ * camera does NOT move until `next()`/`prev()`/`goTo()`. An empty
109
+ * `query.text` is "stop searching" — identical to `clear()`.
110
+ */
111
+ search(query: SearchQuery$1, exec?: SearchExecOptions): void;
112
+ /** Re-run the current query from scratch (used after document mutations). */
113
+ rerun(): void;
114
+ clear(): void;
115
+ /** Advance to the next/previous hit (wraps) and reveal it (see {@link SearchRevealOptions}). */
116
+ next(): SearchHit | null;
117
+ prev(): SearchHit | null;
118
+ /** Jump to a specific hit index and reveal it; `reveal` overrides the plugin defaults. */
119
+ goTo(index: number, reveal?: SearchRevealOptions): SearchHit | null;
120
+ /** The session's query — what a search box renders. Null when idle. */
121
+ query(): SearchQuery$1 | null;
122
+ status(): SearchStatus;
123
+ hits(): SearchHit[];
124
+ hitCount(): number;
125
+ activeIndex(): number;
126
+ activeHit(): SearchHit | null;
127
+ /** Hits on one page — the layer's input. Element identity is stable. */
128
+ hitsForPage(pon: PageObjectNumber): SearchHit[];
129
+ progress(): {
130
+ scanned: number;
131
+ total: number;
132
+ };
133
+ errorMessage(): string | null;
134
+ /**
135
+ * Run a query to completion and return every hit. Touches NO state — no
136
+ * sidebar, no highlights, no camera, no activeIndex; the user's visible
137
+ * search is never superseded. The primitive other features build on
138
+ * (redact-by-term, link detection, occurrence badges). Scans in natural
139
+ * page order; concurrent calls are independent.
140
+ */
141
+ findAll(query: SearchQuery$1, opts?: SearchFindAllOptions): Promise<SearchHit[]>;
142
+ }
143
+ declare const SearchToken: import("@embedpdf/core").CapabilityToken<SearchCapability>;
144
+ //#endregion
145
+ //#region src/search.plugin.d.ts
146
+ /**
147
+ * Document text search over `doc.search` — the engine's budgeted,
148
+ * cursor-resumable slices. Document-scoped; no pointer handling, so it
149
+ * needs no interaction hub. The Stage is optional: when present, scans
150
+ * start at the current page (viewport-first) and hit navigation reveals
151
+ * the hit's page; without it the host owns scrolling.
152
+ */
153
+ declare const searchPlugin: (config?: SearchPluginConfig) => import("@embedpdf/core").PluginDef<SearchState, SearchAction, SearchCapability>;
154
+ //#endregion
155
+ export { type SearchCapability, type SearchExecOptions, type SearchFindAllOptions, type SearchHit, type SearchPluginConfig, type SearchQuery, type SearchQueryIssue, type SearchQueryValidation, type SearchRegexValidation, type SearchRevealOptions, type SearchSnippet, type SearchState, type SearchStatus, SearchToken, searchPlugin, validateSearchQuery, validateSearchRegex };
156
+ //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1 +1,156 @@
1
- export * from './lib';
1
+ import { PageObjectNumber } from "@embedpdf/core";
2
+ import { RevealAnchor, ScrollBehaviorKind } from "@embedpdf/plugin-stage";
3
+ import { Rect } from "@embedpdf/core-geometry";
4
+ import { SearchMode, SearchQuery, SearchQuery as SearchQuery$1, SearchQueryIssue, SearchQueryValidation, SearchRegexValidation, SearchSnippet, SearchSnippet as SearchSnippet$1, validateSearchQuery, validateSearchRegex } from "@embedpdf/engine-core/runtime";
5
+ //#region src/types.d.ts
6
+ /**
7
+ * One match, viewer-shaped: the engine's PDF-space line rects converted to
8
+ * CONTENT space (y-down — the same space selection rects live in), plus the
9
+ * page's display index so navigation can `reveal()` without a lookup.
10
+ * `charStart`/`charCount` keep the engine's text-page offsets, so a hit can
11
+ * later seed a selection or a highlight annotation without re-searching.
12
+ */
13
+ interface SearchHit {
14
+ pon: PageObjectNumber;
15
+ pageIndex: number;
16
+ charStart: number;
17
+ charCount: number;
18
+ rects: Rect[];
19
+ snippet?: SearchSnippet$1;
20
+ }
21
+ /**
22
+ * `searching` means the slice loop is still walking pages — results are
23
+ * usable the moment they appear (matches stream in viewport-first order).
24
+ */
25
+ type SearchStatus = 'idle' | 'searching' | 'complete' | 'error';
26
+ /**
27
+ * Execution options for the session `search()` — HOW the scan runs, never
28
+ * part of what the query MEANS (which is why they're not on `SearchQuery`
29
+ * and are never stored or restored into a search box).
30
+ */
31
+ interface SearchExecOptions {
32
+ /** Scan origin override. Defaults to the Stage's current page (viewport-first). */
33
+ startPage?: PageObjectNumber;
34
+ }
35
+ /** Options for the session-free `findAll()` service. */
36
+ interface SearchFindAllOptions {
37
+ /** Abort the scan; the returned promise rejects with `signal.reason`. */
38
+ signal?: AbortSignal;
39
+ /**
40
+ * Pin the slice mode. Default: `'full'` with automatic `'rects'`
41
+ * fallback when snippets are denied — pass `'rects'` when you only need
42
+ * geometry (e.g. redact-by-term) to skip snippet extraction entirely.
43
+ */
44
+ mode?: SearchMode;
45
+ }
46
+ interface SearchState {
47
+ /**
48
+ * The query in flight/completed, null when idle/cleared — THE stored
49
+ * form of the search intent, the same flat `SearchQuery` the engine
50
+ * matches on, the wire caches by, and a search box renders. Survives
51
+ * any search UI unmounting (results are document-scoped; so is this).
52
+ */
53
+ query: SearchQuery$1 | null;
54
+ status: SearchStatus;
55
+ hits: SearchHit[];
56
+ /** pon → indices into `hits` — the per-page layer's read model. */
57
+ hitsByPage: Record<number, number[]>;
58
+ /** Index into `hits`, -1 = none. */
59
+ activeIndex: number;
60
+ progress: {
61
+ scanned: number;
62
+ total: number;
63
+ };
64
+ error: string | null;
65
+ }
66
+ type SearchAction = {
67
+ type: 'START';
68
+ query: SearchQuery$1;
69
+ } | {
70
+ type: 'APPEND';
71
+ hits: SearchHit[];
72
+ scanned: number;
73
+ total: number;
74
+ } | {
75
+ type: 'COMPLETE';
76
+ } | {
77
+ type: 'ERROR';
78
+ message: string;
79
+ } | {
80
+ type: 'SET_ACTIVE';
81
+ index: number;
82
+ } | {
83
+ type: 'CLEAR';
84
+ };
85
+ /**
86
+ * How hit navigation arrives (forwarded to the Stage's positioned reveal).
87
+ * The default is the browser find-bar feel: the hit lands at the top-middle
88
+ * of the viewport (`anchor: { y: 0.35 }`), horizontal only moves when the
89
+ * hit is off-screen, zoom never changes, smooth tween.
90
+ */
91
+ interface SearchRevealOptions {
92
+ anchor?: RevealAnchor;
93
+ behavior?: ScrollBehaviorKind;
94
+ }
95
+ interface SearchPluginConfig {
96
+ /** Arrival defaults for `next()`/`prev()`/`goTo()`. */
97
+ reveal?: SearchRevealOptions;
98
+ }
99
+ /**
100
+ * The search plugin is a find SERVICE plus one user-visible search SESSION
101
+ * per document. `findAll` is the service; `search` is the session; the
102
+ * sidebar, the highlights layer, and next/prev render the session.
103
+ */
104
+ interface SearchCapability {
105
+ /**
106
+ * Start a new search (supersedes and aborts any running one). Results
107
+ * stream into state slice by slice; the first hit becomes active but the
108
+ * camera does NOT move until `next()`/`prev()`/`goTo()`. An empty
109
+ * `query.text` is "stop searching" — identical to `clear()`.
110
+ */
111
+ search(query: SearchQuery$1, exec?: SearchExecOptions): void;
112
+ /** Re-run the current query from scratch (used after document mutations). */
113
+ rerun(): void;
114
+ clear(): void;
115
+ /** Advance to the next/previous hit (wraps) and reveal it (see {@link SearchRevealOptions}). */
116
+ next(): SearchHit | null;
117
+ prev(): SearchHit | null;
118
+ /** Jump to a specific hit index and reveal it; `reveal` overrides the plugin defaults. */
119
+ goTo(index: number, reveal?: SearchRevealOptions): SearchHit | null;
120
+ /** The session's query — what a search box renders. Null when idle. */
121
+ query(): SearchQuery$1 | null;
122
+ status(): SearchStatus;
123
+ hits(): SearchHit[];
124
+ hitCount(): number;
125
+ activeIndex(): number;
126
+ activeHit(): SearchHit | null;
127
+ /** Hits on one page — the layer's input. Element identity is stable. */
128
+ hitsForPage(pon: PageObjectNumber): SearchHit[];
129
+ progress(): {
130
+ scanned: number;
131
+ total: number;
132
+ };
133
+ errorMessage(): string | null;
134
+ /**
135
+ * Run a query to completion and return every hit. Touches NO state — no
136
+ * sidebar, no highlights, no camera, no activeIndex; the user's visible
137
+ * search is never superseded. The primitive other features build on
138
+ * (redact-by-term, link detection, occurrence badges). Scans in natural
139
+ * page order; concurrent calls are independent.
140
+ */
141
+ findAll(query: SearchQuery$1, opts?: SearchFindAllOptions): Promise<SearchHit[]>;
142
+ }
143
+ declare const SearchToken: import("@embedpdf/core").CapabilityToken<SearchCapability>;
144
+ //#endregion
145
+ //#region src/search.plugin.d.ts
146
+ /**
147
+ * Document text search over `doc.search` — the engine's budgeted,
148
+ * cursor-resumable slices. Document-scoped; no pointer handling, so it
149
+ * needs no interaction hub. The Stage is optional: when present, scans
150
+ * start at the current page (viewport-first) and hit navigation reveals
151
+ * the hit's page; without it the host owns scrolling.
152
+ */
153
+ declare const searchPlugin: (config?: SearchPluginConfig) => import("@embedpdf/core").PluginDef<SearchState, SearchAction, SearchCapability>;
154
+ //#endregion
155
+ export { type SearchCapability, type SearchExecOptions, type SearchFindAllOptions, type SearchHit, type SearchPluginConfig, type SearchQuery, type SearchQueryIssue, type SearchQueryValidation, type SearchRegexValidation, type SearchRevealOptions, type SearchSnippet, type SearchState, type SearchStatus, SearchToken, searchPlugin, validateSearchQuery, validateSearchRegex };
156
+ //# sourceMappingURL=index.d.ts.map