dirsql 0.4.34 → 0.4.36

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.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `require.resolve`-shaped seam. Injectable so unit tests can fake module
3
+ * resolution without a real `node_modules` layout.
4
+ */
5
+ export interface PackageResolver {
6
+ /** Resolve a specifier to an on-disk path (`require.resolve`). */
7
+ resolve(specifier: string): string;
8
+ /** Candidate `node_modules` dirs for a specifier (`require.resolve.paths`). */
9
+ paths(specifier: string): string[] | null;
10
+ }
11
+ /** Locate the on-disk package directory for a bare name. */
12
+ export declare function packageDir(name: string, resolver: PackageResolver): string;
@@ -0,0 +1,24 @@
1
+ // Locate an installed package's directory from a bare name, for extension
2
+ // resolution.
3
+ import { existsSync, statSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ /** Locate the on-disk package directory for a bare name. */
6
+ export function packageDir(name, resolver) {
7
+ // The package.json's directory is the package root. Preferred because it is
8
+ // unaffected by an `exports` map that hides the main entry.
9
+ try {
10
+ const pkgJson = resolver.resolve(`${name}/package.json`);
11
+ return pkgJson.slice(0, pkgJson.length - "/package.json".length);
12
+ }
13
+ catch {
14
+ // `exports` may forbid resolving package.json; fall back to scanning the
15
+ // candidate node_modules dirs for `<dir>/<name>`.
16
+ }
17
+ for (const dir of resolver.paths(name) ?? []) {
18
+ const candidate = join(dir, name);
19
+ if (existsSync(candidate) && statSync(candidate).isDirectory()) {
20
+ return candidate;
21
+ }
22
+ }
23
+ throw new Error(`could not resolve extension package '${name}': not installed`);
24
+ }
@@ -1,13 +1,4 @@
1
- /**
2
- * `require.resolve`-shaped seam. Injectable so unit tests can fake module
3
- * resolution without a real `node_modules` layout.
4
- */
5
- export interface PackageResolver {
6
- /** Resolve a specifier to an on-disk path (`require.resolve`). */
7
- resolve(specifier: string): string;
8
- /** Candidate `node_modules` dirs for a specifier (`require.resolve.paths`). */
9
- paths(specifier: string): string[] | null;
10
- }
1
+ import { type PackageResolver } from "./package-dir.js";
11
2
  /** True when `path` is a bare package name rather than a file path. */
12
3
  export declare function isBareName(path: string): boolean;
13
4
  /**
@@ -14,6 +14,7 @@
14
14
  import { existsSync, readdirSync, statSync } from "node:fs";
15
15
  import { createRequire } from "node:module";
16
16
  import { isAbsolute, join, resolve as resolvePath } from "node:path";
17
+ import { packageDir } from "./package-dir.js";
17
18
  // Suffixes that mark a value as "already a file path" (so package resolution is
18
19
  // never attempted).
19
20
  const LOADABLE_SUFFIXES = [".so", ".dylib", ".dll", ".node"];
@@ -41,26 +42,6 @@ export function isBareName(path) {
41
42
  }
42
43
  return !LOADABLE_SUFFIXES.some((s) => path.endsWith(s));
43
44
  }
44
- /** Locate the on-disk package directory for a bare name. */
45
- function packageDir(name, resolver) {
46
- // The package.json's directory is the package root. Preferred because it is
47
- // unaffected by an `exports` map that hides the main entry.
48
- try {
49
- const pkgJson = resolver.resolve(`${name}/package.json`);
50
- return pkgJson.slice(0, pkgJson.length - "/package.json".length);
51
- }
52
- catch {
53
- // `exports` may forbid resolving package.json; fall back to scanning the
54
- // candidate node_modules dirs for `<dir>/<name>`.
55
- }
56
- for (const dir of resolver.paths(name) ?? []) {
57
- const candidate = join(dir, name);
58
- if (existsSync(candidate) && statSync(candidate).isDirectory()) {
59
- return candidate;
60
- }
61
- }
62
- throw new Error(`could not resolve extension package '${name}': not installed`);
63
- }
64
45
  /** Glob the platform loadable inside a bare name's package dir. */
65
46
  function resolvePackage(name, resolver) {
66
47
  const dir = packageDir(name, resolver);
@@ -498,6 +498,24 @@ and, when the query ends:
498
498
  dirsql: ran 41231 worker calls in 2m41s
499
499
  ```
500
500
 
501
+ A worker that keeps a cache of its own can say so per response
502
+ (`{"meta": {"cached": true}}` — see [Worker
503
+ protocol](./config.md#worker-protocol)), and those round trips are then split
504
+ out, because the number that answers *"will this be fast next time"* is not
505
+ the total:
506
+
507
+ ```
508
+ dirsql: running 9204 worker calls (8811 cached)
509
+ dirsql: ran 41231 worker calls in 2m41s (38104 cached)
510
+ ```
511
+
512
+ Both figures count **worker round trips, not rows**. A function declared
513
+ `deterministic = true` lets SQLite reuse one answer for identical arguments
514
+ within a query, so repeated content never reaches the worker at all and both
515
+ numbers sit below the row count on a corpus with duplicates. The split covers
516
+ only what the worker itself reports serving from cache. A worker that sends no
517
+ `meta` gets the unsplit line above, not a `(0 cached)`.
518
+
501
519
  A query that calls no worker prints nothing, whatever the setting — the
502
520
  reporting only ever speaks when there is something to report.
503
521
 
@@ -161,6 +161,15 @@ request line in, one response line out, per call:
161
161
  JSON-text vectors) — or `{"err": "message"}`, which **fails the query**
162
162
  with that message. An `{"err": ...}` response leaves the healthy worker
163
163
  running; only transport failures (timeout, crash) recycle it.
164
+ - **Optional `"meta"`**, alongside `"ok"`: a second top-level object carrying
165
+ facts about how the answer was produced rather than what it is. One key is
166
+ read today — `{"ok": [...], "meta": {"cached": true}}` says the worker
167
+ answered from a cache of its own, which dirsql reports as the `(N cached)`
168
+ split on its [worker-call progress line](./cli.md#progress-reporting). The
169
+ field is **optional and advisory**: a worker that omits it is a worker that
170
+ reports no cache hits, keys dirsql does not recognize are ignored (they
171
+ always have been), and a `meta` of an unexpected shape is ignored too rather
172
+ than failing a query over a progress counter.
164
173
  - **stderr passes through** to `dirsql`'s stderr, so a worker's progress
165
174
  bars and download logs reach the terminal.
166
175
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dirsql",
3
- "version": "0.4.34",
3
+ "version": "0.4.36",
4
4
  "description": "Ephemeral SQL index over a local directory",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/thekevinscott/dirsql",
@@ -213,10 +213,10 @@
213
213
  ]
214
214
  },
215
215
  "optionalDependencies": {
216
- "@dirsql/lib-linux-x64-gnu": "0.4.34",
217
- "@dirsql/lib-linux-arm64-gnu": "0.4.34",
218
- "@dirsql/lib-darwin-x64": "0.4.34",
219
- "@dirsql/lib-darwin-arm64": "0.4.34",
220
- "@dirsql/lib-win32-x64-msvc": "0.4.34"
216
+ "@dirsql/lib-linux-x64-gnu": "0.4.36",
217
+ "@dirsql/lib-linux-arm64-gnu": "0.4.36",
218
+ "@dirsql/lib-darwin-x64": "0.4.36",
219
+ "@dirsql/lib-darwin-arm64": "0.4.36",
220
+ "@dirsql/lib-win32-x64-msvc": "0.4.36"
221
221
  }
222
222
  }