@deepseek-ai/dsh-session-query-sqlite 0.0.1-rc.1
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.
- package/LICENSE +28 -0
- package/README.i18n.yaml +6 -0
- package/README.md +57 -0
- package/README.zh.md +57 -0
- package/lib/index.js +1129 -0
- package/lib/invariant.js +23 -0
- package/lib/types/index.d.ts +103 -0
- package/lib/types/invariant.d.ts +16 -0
- package/lib/types/query.d.ts +106 -0
- package/lib/types/schema.d.ts +16 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, DeepSeek
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.i18n.yaml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/session-query/session-query-sqlite/README.md
|
|
5
|
+
README.md: 8784f1b2c2a3c9291b761c0a6e68201286b9e306
|
|
6
|
+
README.zh.md: 5b69c054a0e17a49e9c709b27e497b006a024a91
|
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-session-query-sqlite
|
|
2
|
+
|
|
3
|
+
English | [中文](README.zh.md)
|
|
4
|
+
|
|
5
|
+
Concrete `ctx.sessionQuery` provider. `SessionQuerySqlite` inherits exact reads, traces, and provider-independent filters from the Service Definition package and implements its two full-text methods with SQLite FTS5. Search uses the live-preferred logical session corpus and groups cross-session results by their strongest event.
|
|
6
|
+
|
|
7
|
+
## Search contract
|
|
8
|
+
|
|
9
|
+
`searchSessions(request, exec?)` returns `SessionSearchHit` pages across the corpus; `searchEvents(request, exec?)` returns `SessionEventSearchHit` pages within one session. Queries are required, trimmed, whitespace-normalized literal phrases. FTS5 syntax such as quotes, `OR`, `NEAR`, and `*` is treated as data rather than executable MATCH syntax. Metadata filters are parameterized SQL predicates applied before ranking. To keep SQLite FTS5 MATCH in a supported outer-predicate context, cross-session requests may compile at most 14 combined session and event filter predicates; within-session requests may compile at most 13 filter predicates because the fixed target-session predicate consumes one slot. Each range endpoint compiles as one predicate. A request exceeding either predicate budget or SQLite's portable limit of 32,766 total bindings, including fixed query and pagination values, fails with `SESSION_QUERY_INVALID_FILTER` before statement preparation.
|
|
10
|
+
|
|
11
|
+
Relevance is source-comparable across persistent and TEMP tables: actual FTS5 highlighted-match span count descending, then stored document code-point length ascending. Event time, session id where applicable, and seq break remaining ties. Cross-session results expose the selected event as `bestMatch`; both scopes derive whitespace-normalized plain text from FTS5 highlight positions and bound it in Unicode code points. Cursors are opaque branded values, bind to the normalized request and service instance, and fail when the relevant generation changes. A within-session cursor survives unrelated-session changes; a cross-session cursor does not.
|
|
12
|
+
|
|
13
|
+
All three surfaces (`current`, `shadowed`, and `log-only`) are searchable by default. Pass a surface filter to narrow them.
|
|
14
|
+
|
|
15
|
+
## Source and index lifecycle
|
|
16
|
+
|
|
17
|
+
The service requires `ctx.sessions` and observes optional `ctx.sessionPersistence` dynamically. One serialized state machine compares source-qualified lightweight durable snapshot revisions, non-mutatingly inspects only new or changed logs, extracts shared semantic documents, reconciles changes transactionally, and runs the query. Session queries never invoke the persistence backend's crash-repairing `load()`; an owner attaching during inspection cannot mutate its log, and the stable-observation retry makes the result live-preferred. The TEMP live row still records persisted availability, and the durable base refreshes after that live owner detaches. Repeated queries and an unchanged same-store reopen perform no full durable-log inspection; switching stores, or observing new, changed, deleted, or externally load-repaired sources, reconciles on the next stable observation. Source or transaction failure commits nothing, and the next search retries.
|
|
18
|
+
|
|
19
|
+
`openAt: startup` is the default: service activation imports `node:sqlite`, opens the handle, and fails before publication when the index is invalid. `openAt: first-search` publishes the service as ACTIVE without importing the SQLite module or opening a handle; the first concurrent searches share one readiness promise, and disposal before any search opens nothing. This mode supports compositions that need clean Node 22 startup output by deferring SQLite's experimental warning until the first actual search; it does not suppress a warning at that point. An invalid database likewise fails the first search instead of service activation.
|
|
20
|
+
|
|
21
|
+
Persisted FTS rows live in a dedicated derived database. Connection-local TEMP tables hold live rows, which shadow the durable base for the same session and reveal it when the live owner disappears. Unmounting persistence hides durable rows without discarding the cache; remounting reconciles it. Closing or reopening the database drops every live overlay while retaining persisted rows.
|
|
22
|
+
|
|
23
|
+
The database is disposable but reset is guarded: every recognized schema version rejects unknown user tables before mutating journal mode, and only a recognized incompatible schema containing derived tables rebuilds in place. An unrelated or canonical database is refused. Never point `path` at the session-persistence database. On filesystems with POSIX modes, missing directories and databases are created owner-only (`0700` and `0600` before the process umask), and SQLite sidecars inherit the database mode; existing modes are preserved. Exactly one service in one process owns a derived-index path; external writers or a second process are unsupported because generations and TEMP shadow state are connection-owned.
|
|
24
|
+
|
|
25
|
+
## Configuration
|
|
26
|
+
|
|
27
|
+
| Key | Default | Contract |
|
|
28
|
+
|---|---:|---|
|
|
29
|
+
| `path` | required | Dedicated derived-index SQLite path; `:memory:` is supported. Missing filesystem paths are created owner-only on POSIX filesystems. |
|
|
30
|
+
| `openAt` | `startup` | `startup` opens before service activation completes; `first-search` defers the SQLite module and handle until search. |
|
|
31
|
+
| `journalMode` | `wal` | `wal`, `delete`, `truncate`, or `persist`. |
|
|
32
|
+
| `defaultLimit` | `20` | Page size when a request omits `limit`; at most `Number.MAX_SAFE_INTEGER - 1`. |
|
|
33
|
+
| `maxLimit` | `100` | Largest accepted request page size; at most `Number.MAX_SAFE_INTEGER - 1`. |
|
|
34
|
+
| `snippetChars` | `240` | Maximum snippet length in Unicode code points. |
|
|
35
|
+
| `readWindowMax` | `50` | Maximum `before` or `after` raw-event count for inherited `readEvent()`. |
|
|
36
|
+
| `persistedInspectConcurrency` | `4` | Maximum concurrent persisted-log inspections for inherited batch reads; must be a positive safe integer. |
|
|
37
|
+
|
|
38
|
+
## Tokenizer and limits
|
|
39
|
+
|
|
40
|
+
The index uses FTS5 `unicode61`. The trade-off is token/phrase recall rather than arbitrary substring recall: `AI` does not match the token `BRAID`. Use `ctx.sessionQuery.filterEvents()` with a `text` clause when a literal whitespace-flexible substring scan is required. NUL is rejected in queries; reserved highlight markers and NUL in documents are normalized before indexing so presentation markers cannot collide with source text.
|
|
41
|
+
|
|
42
|
+
Abort signals stop queued work and flow unchanged through snapshot listing and non-mutating inspection. Once source work starts, the serialized state machine awaits that backend promise itself—even when a backend ignores cancellation—then checks the signal before starting any further listing, inspection, reconciliation, or query work. The caller therefore observes cancellation only after started backend work is quiescent, and a later search cannot enter the serializer while that cleanup is pending. Node's synchronous `DatabaseSync` API cannot interrupt a metadata or MATCH statement already executing on the JavaScript thread; signals are checked immediately before and after those non-preemptible calls.
|
|
43
|
+
|
|
44
|
+
## Model Experience
|
|
45
|
+
|
|
46
|
+
None, as this trusted search backend returns hits only to callers and registers no model-facing prompt, schema, tool, or message.
|
|
47
|
+
|
|
48
|
+
#### KV Cache effect
|
|
49
|
+
|
|
50
|
+
None; this package neither assembles nor sends a provider request.
|
|
51
|
+
|
|
52
|
+
## Known Limitations and Deferred Work
|
|
53
|
+
|
|
54
|
+
- **No caller authorization** — this is a trusted context-wide service; a model tool or UI must enforce its own access policy.
|
|
55
|
+
- **Synchronous query execution** — `DatabaseSync` blocks the JavaScript thread during MATCH execution and cannot interrupt a statement already running.
|
|
56
|
+
- **Token recall, not arbitrary substrings** — the `unicode61` tokenizer does not match substrings inside a larger token; use `filterEvents()` for literal scans.
|
|
57
|
+
- **Single-owner derived index** — one service in one process must own each index path; external writers and multi-process sharing are unsupported.
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# @deepseek-ai/dsh-session-query-sqlite
|
|
2
|
+
|
|
3
|
+
[English](README.md) | 中文
|
|
4
|
+
|
|
5
|
+
具体 `ctx.sessionQuery` 提供方。`SessionQuerySqlite` 从 Service Definition 包继承精确读取、跟踪和提供方无关的过滤,并使用 SQLite FTS5 实现其两个全文方法。搜索使用实时优先的逻辑会话语料库,并按每个会话中匹配度最高的事件对跨会话结果分组。
|
|
6
|
+
|
|
7
|
+
## 搜索约定
|
|
8
|
+
|
|
9
|
+
`searchSessions(request, exec?)` 返回跨语料库的 `SessionSearchHit` 分页结果;`searchEvents(request, exec?)` 返回单个会话内的 `SessionEventSearchHit` 分页结果。查询不得省略,首尾空白会被移除,内部空白会被规范化,并按字面短语处理。引号、`OR`、`NEAR` 和 `*` 等 FTS5 语法被视为数据,而非可执行 MATCH 语法。元数据过滤器是在排名前应用的参数化 SQL 谓词。为使 SQLite FTS5 MATCH 保持在受支持的外层谓词上下文中,跨会话请求最多可编译 14 个组合会话与事件过滤谓词;会话内请求最多可编译 13 个过滤谓词,因为固定目标会话谓词占用一个槽位。每个范围端点编译为一个谓词。请求超过任一谓词预算,或超过 SQLite 可移植的 32,766 总绑定上限(包括固定查询和分页值)时,会在准备语句前以 `SESSION_QUERY_INVALID_FILTER` 失败。
|
|
10
|
+
|
|
11
|
+
持久表和 TEMP 表之间的相关性排名可直接比较:先按实际 FTS5 高亮匹配 span 数降序,再按已存储文档码点长度升序。事件时间、适用时的会话 id 和 seq 打破其余平局。跨会话结果将所选事件公开为 `bestMatch`;两种范围都从 FTS5 高亮位置派生空白规范化的纯文本,并按 Unicode 码点限制长度。游标是带品牌类型的不透明值,绑定到规范化请求和服务实例,并在相关世代变更时失败。会话内游标可在不相关会话变更后延续使用;跨会话游标则不能。
|
|
12
|
+
|
|
13
|
+
默认可搜索全部三种接口(`current`、`shadowed` 和 `log-only`)。传入接口过滤器可缩小范围。
|
|
14
|
+
|
|
15
|
+
## 来源与索引生命周期
|
|
16
|
+
|
|
17
|
+
该服务需要 `ctx.sessions`,并动态观察可选的 `ctx.sessionPersistence`。一个串行化状态机比较来源限定的轻量持久化快照修订,仅以不修改日志的方式检查新日志或已更改日志,提取共享语义文档,以事务方式对账变更,然后运行查询。会话查询绝不会调用持久化后端会修复崩溃的 `load()`;检查期间接入的活动所有者无法修改其日志,稳定观察重试使结果优先使用实时来源。TEMP 实时行仍会记录持久化可用性,而持久基库会在该活动所有者脱离后刷新。重复查询和未变的同存储重新打开不会执行完整持久化日志检查;切换存储,或观察到新增、已更改、已删除或经外部 load 修复的来源时,会在下次稳定观察时对账。来源或事务失败不会提交任何内容,下一次搜索会重试。
|
|
18
|
+
|
|
19
|
+
`openAt: startup` 是默认值:服务激活会导入 `node:sqlite` 并打开句柄;如果索引无效,则会在服务发布前失败。`openAt: first-search` 会将服务以 ACTIVE 状态发布,同时不导入 SQLite 模块也不打开句柄;首批并发搜索共享同一个就绪 promise,在任何搜索前处置服务时也不会导入模块或打开句柄。此模式通过把 SQLite 的实验性警告推迟到首次实际搜索,支持需要干净 Node 22 启动输出的组合;它不会抑制届时的警告。无效数据库同样会使首次搜索失败,而不是服务激活失败。
|
|
20
|
+
|
|
21
|
+
持久化 FTS 行位于专用派生数据库中。连接本地 TEMP 表保存实时行,这些行会遮蔽同一会话的持久化基库,并在实时所有者消失后使其重新可见。卸载持久化会隐藏持久行,但不会丢弃缓存;重新挂载会对账缓存。关闭或重新打开数据库会删除全部实时覆盖层,但保留持久行。
|
|
22
|
+
|
|
23
|
+
该数据库虽可丢弃重建,但 reset 操作受到保护:每个已识别 schema 版本都会在修改 journal mode 前拒绝未知用户表;只有包含派生表的已识别不兼容 schema 才会原地重建。不相关数据库或规范数据库将被拒绝。绝不能将 `path` 指向 session-persistence 数据库。在具有 POSIX mode 的文件系统上,缺失的目录和数据库会以仅所有者可访问的方式创建(进程 umask 前为 `0700` 和 `0600`),SQLite sidecar 继承数据库 mode;现有 mode 保持不变。每个派生索引路径在一个进程中只能由一个服务拥有;不支持外部写入者或第二个进程,因为世代和 TEMP 遮蔽状态由连接持有。
|
|
24
|
+
|
|
25
|
+
## 配置
|
|
26
|
+
|
|
27
|
+
| 键 | 默认值 | 约定 |
|
|
28
|
+
|---|---:|---|
|
|
29
|
+
| `path` | 必填 | 专用派生索引 SQLite 路径;支持 `:memory:`。在 POSIX 文件系统上,缺失的文件系统路径会以仅所有者可访问的方式创建。 |
|
|
30
|
+
| `openAt` | `startup` | `startup` 会在服务激活完成前打开;`first-search` 把 SQLite 模块与句柄推迟到搜索时再加载和打开。 |
|
|
31
|
+
| `journalMode` | `wal` | `wal`、`delete`、`truncate` 或 `persist`。 |
|
|
32
|
+
| `defaultLimit` | `20` | 请求省略 `limit` 时的分页大小;最多为 `Number.MAX_SAFE_INTEGER - 1`。 |
|
|
33
|
+
| `maxLimit` | `100` | 接受的最大请求分页大小;最多为 `Number.MAX_SAFE_INTEGER - 1`。 |
|
|
34
|
+
| `snippetChars` | `240` | 按 Unicode 码点计算的最大 snippet 长度。 |
|
|
35
|
+
| `readWindowMax` | `50` | `before` 或 `after` 的最大原始事件数,用于继承的 `readEvent()`。 |
|
|
36
|
+
| `persistedInspectConcurrency` | `4` | 继承批量读取的最大并发持久化日志检查数;必须是正安全整数。 |
|
|
37
|
+
|
|
38
|
+
## 分词器与限制
|
|
39
|
+
|
|
40
|
+
该索引使用 FTS5 `unicode61`。取舍是 token/短语召回而非任意子字符串召回:`AI` 不匹配 token `BRAID`。需要执行字面的空白弹性子字符串扫描时,使用 `ctx.sessionQuery.filterEvents()` 并传入 `text` 子句。查询会拒绝 NUL;文档中的保留高亮标记和 NUL 会在索引前被规范化,使展示标记无法与源文本冲突。
|
|
41
|
+
|
|
42
|
+
中止信号会停止已排队工作,并原样流经快照枚举和非修改式检查。来源工作一旦开始,串行化状态机会自行等待该后端 promise,即使后端忽略取消,之后也会在启动任何进一步的枚举、检查、对账或查询工作前检查信号。因此,调用方只会在已启动后端工作完全停稳后观察到取消,而后续搜索在该清理尚未完成时无法进入 serializer。Node 的同步 `DatabaseSync` API 无法中断已在 JavaScript 线程上执行的元数据或 MATCH 语句;系统会在这些不可抢占调用前后立即检查信号。
|
|
43
|
+
|
|
44
|
+
## 模型体验
|
|
45
|
+
|
|
46
|
+
无。该可信搜索后端只向调用方返回命中,不注册面向模型的提示词、schema、工具或消息。
|
|
47
|
+
|
|
48
|
+
#### KV Cache 影响
|
|
49
|
+
|
|
50
|
+
无;该包既不组装也不发送提供方请求。
|
|
51
|
+
|
|
52
|
+
## 已知限制与暂缓事项
|
|
53
|
+
|
|
54
|
+
- **无调用方授权**:这是上下文范围内的可信服务;模型工具或 UI 必须强制执行自己的访问策略。
|
|
55
|
+
- **同步查询执行**:`DatabaseSync` 在 MATCH 执行期间会阻塞 JavaScript 线程,且无法中断已运行的语句。
|
|
56
|
+
- **Token 召回,而非任意子字符串**:`unicode61` tokenizer 不会匹配更大 token 中的子字符串;对字面扫描使用 `filterEvents()`。
|
|
57
|
+
- **单一所有者的派生索引**:每个索引路径必须仅归一个进程中的一个服务所有;不支持外部写入者和多进程共享。
|