@adhd/sox-embedding-provider 0.5.1 → 0.5.2

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,120 @@
1
+ /**
2
+ * embedHostConfig.ts — config + stable socket/singleton-key resolution for the
3
+ * embedding funnel (SPEC-EMBEDDING-FUNNEL.md §B).
4
+ *
5
+ * The funnel collapses N consumer processes onto ONE peer-spawned, self-reaping
6
+ * ONNX host per `(model, execution-provider, cacheDir)`. That requires a
7
+ * deterministic, machine-wide identity for "the one host for this workload":
8
+ *
9
+ * - {@link embedHostSingletonKey} — the [def:singleton-key] every consumer
10
+ * computes identically, so `ensureBackend()`'s O_EXCL spawn-lock collapses a
11
+ * thundering herd to one spawn.
12
+ * - {@link embedHostSocketPath} — the UDS path derived from that key via
13
+ * `backendSocketPath()` (the SAME derivation the service-proxy uses, so
14
+ * there is never a port-selection problem and never a clash).
15
+ *
16
+ * ── Host selection is typed config, never an env toggle (ADR-0013) ─────────────
17
+ *
18
+ * `host` is a closed union (`'shared' | 'private'`) carried on
19
+ * `EmbeddingProviderConfig.host` and reported in `health()`. There is
20
+ * deliberately NO `SOX_EMBED_HOST=shared|private` variable: a behavior switch
21
+ * must be visible, validated, and auditable, not an ambient string. The only
22
+ * env reads here are ADR-0013 D3/D5 shapes:
23
+ *
24
+ * - `SOX_EMBED_HOST_IDLE_GRACE_MS` — a numeric tuning constant (D3): how long
25
+ * the host lingers after its last client leaves. Additive/numeric only.
26
+ * - `SOX_ECOSYSTEM_HOME` — host config (D5): where the socket lives.
27
+ * - `SOX_EMBED_HOST_MAIN` / `SOX_EMBED_HOST_SOCKET` — host-injected transport
28
+ * config (D5) / test seams; they select a path, they never enable a feature.
29
+ *
30
+ * Leaf module — node builtins only (fs, os, path, url, crypto, module) plus
31
+ * `backendSocketPath` from `@adhd/sox-service-proxy`.
32
+ */
33
+ /** The host-selection closed union (ADR-0013). `'shared'` is the default. */
34
+ export type EmbedHostMode = 'shared' | 'private';
35
+ /** Resolved funnel configuration. */
36
+ export interface EmbedHostConfig {
37
+ /** `'shared'` (default): funnel through the peer-spawned host. `'private'`: the pre-funnel per-process fork (CI/diagnostics). */
38
+ host: EmbedHostMode;
39
+ /** The directory the host UDS is created under (ADR-0004: `$SOX_ECOSYSTEM_HOME/run`). */
40
+ socketDir: string;
41
+ /** How long the host lingers with zero clients and zero in-flight work before it reaps itself. */
42
+ idleGraceMs: number;
43
+ }
44
+ /**
45
+ * Bumped whenever the host's wire protocol or behavior changes incompatibly.
46
+ *
47
+ * Open question #4 in SPEC-EMBEDDING-FUNNEL.md ("a running host is an old
48
+ * build") is resolved with this constant rather than the npm package version.
49
+ * Rationale: the real hazard is a host whose `embedding.*` contract the new
50
+ * consumer cannot speak — a *protocol* change — not every cosmetic patch. Keying
51
+ * on the npm version would spawn a brand-new host on every patch bump (briefly
52
+ * two hosts, defeating the funnel across an upgrade window) while the explicit
53
+ * protocol version forces a new socket exactly when compatibility actually
54
+ * breaks. Bump this with any change to the `embedding.*` method set, the payload
55
+ * shape, or the response shape in `embedHostMain.ts`.
56
+ */
57
+ export declare const EMBED_HOST_PROTOCOL_VERSION = 1;
58
+ /** Default grace before a zero-client host reaps itself. Sized to the short-lived-CLI arrival cadence. */
59
+ export declare const DEFAULT_EMBED_HOST_IDLE_GRACE_MS = 30000;
60
+ /**
61
+ * Apply the typed `host` field from an `EmbeddingProviderConfig`. Passing
62
+ * `undefined` leaves the current posture unchanged (so a `remote` provider
63
+ * without a `host` field never resets a deliberate `'private'` selection).
64
+ */
65
+ export declare function configureEmbedHostHost(host: EmbedHostMode | undefined): void;
66
+ /** TEST-ONLY: clear the process-wide host override back to the `'shared'` default. */
67
+ export declare function __resetEmbedHostConfigForTests(): void;
68
+ /**
69
+ * Resolve the funnel configuration. `host` defaults to `'shared'`; `idleGraceMs`
70
+ * is a numeric tuning constant (ADR-0013 D3) with a hard default.
71
+ */
72
+ export declare function resolveEmbedHostConfig(): EmbedHostConfig;
73
+ /**
74
+ * ADR-0013 D3 tuning constant: `SOX_EMBED_HOST_IDLE_GRACE_MS`. A non-positive or
75
+ * non-numeric value is rejected loudly (never silently treated as "off").
76
+ */
77
+ export declare function resolveEmbedHostIdleGraceMs(): number;
78
+ /**
79
+ * ADR-0004 D5: the host socket lives under `$SOX_ECOSYSTEM_HOME/run` (the user
80
+ * data root's `run/` dir). Mirrors `@adhd/sox-host-runtime`'s `runDir()` without
81
+ * importing it — this package is a low-tier leaf and must not gain a
82
+ * host-runtime dependency. `SOX_ECOSYSTEM_HOME` defaults to `~/.adhd/sox-ecosystem`
83
+ * exactly as `data-paths.ts`'s `DATA_SUBDIR` does.
84
+ */
85
+ export declare function resolveEmbedHostSocketDir(): string;
86
+ /**
87
+ * The machine-wide [def:singleton-key] for the host serving `(modelId, ep,
88
+ * cacheDir)`. Identical inputs ⇒ identical key ⇒ identical socket ⇒ one host,
89
+ * across every consumer process on the box.
90
+ *
91
+ * `cacheDirDigest` is a short sha256 of the ABSOLUTE cache dir, so two stores
92
+ * pointed at different model caches never collide onto one host. The protocol
93
+ * version is appended (see {@link EMBED_HOST_PROTOCOL_VERSION}).
94
+ */
95
+ export declare function embedHostSingletonKey(modelId: string, ep: string, cacheDir: string): string;
96
+ /** Derive the host UDS path from the resolved config and singleton key. */
97
+ export declare function embedHostSocketPath(cfg: EmbedHostConfig, key: string): string;
98
+ /**
99
+ * Resolve the runnable host entrypoint to spawn.
100
+ *
101
+ * Order:
102
+ * 1. `SOX_EMBED_HOST_MAIN` (D5/test seam) — a path injection, never a feature
103
+ * toggle. Used by the funnel teeth suite to run the host from source via a
104
+ * tsx shim without a prior build.
105
+ * 2. A `__dirname` sibling (`dist/embedHostMain.js`) — the npm AND bundled
106
+ * case. The literal `join(__dirname, 'embedHostMain.js')` is load-bearing:
107
+ * `bundle-extension.cjs`'s `verifySidecarReferences()` scans emitted files
108
+ * for exactly this shape, so the sidecar can never ship missing (BL-259).
109
+ * 3. `src/../dist/embedHostMain.js` — vitest's `src/`-resident `__dirname`.
110
+ * 4. `require.resolve('@adhd/sox-embedding-provider/embed-host')` — the
111
+ * package `exports` subpath, when self-reference is available.
112
+ */
113
+ export declare function resolveEmbedHostMainPath(): string;
114
+ /**
115
+ * Where the detached host's stderr is redirected (its stdout/stdin are severed).
116
+ * Kept beside the socket so a wedged host's startup diagnostics are greppable
117
+ * without inheriting any caller fd ([inv:no-fd-inherit], BL-67).
118
+ */
119
+ export declare function resolveEmbedHostStderrLogPath(cfg: EmbedHostConfig): string;
120
+ //# sourceMappingURL=embedHostConfig.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedHostConfig.d.ts","sourceRoot":"","sources":["../src/embedHostConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAYH,6EAA6E;AAC7E,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEjD,qCAAqC;AACrC,MAAM,WAAW,eAAe;IAC9B,iIAAiI;IACjI,IAAI,EAAE,aAAa,CAAC;IACpB,yFAAyF;IACzF,SAAS,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,0GAA0G;AAC1G,eAAO,MAAM,gCAAgC,QAAS,CAAC;AAcvD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,GAAG,IAAI,CAM5E;AAED,sFAAsF;AACtF,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAMxD;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,CAUpD;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAIlD;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG3F;AAED,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAgBjD;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,CAE1E"}
@@ -0,0 +1,180 @@
1
+ /**
2
+ * embedHostConfig.ts — config + stable socket/singleton-key resolution for the
3
+ * embedding funnel (SPEC-EMBEDDING-FUNNEL.md §B).
4
+ *
5
+ * The funnel collapses N consumer processes onto ONE peer-spawned, self-reaping
6
+ * ONNX host per `(model, execution-provider, cacheDir)`. That requires a
7
+ * deterministic, machine-wide identity for "the one host for this workload":
8
+ *
9
+ * - {@link embedHostSingletonKey} — the [def:singleton-key] every consumer
10
+ * computes identically, so `ensureBackend()`'s O_EXCL spawn-lock collapses a
11
+ * thundering herd to one spawn.
12
+ * - {@link embedHostSocketPath} — the UDS path derived from that key via
13
+ * `backendSocketPath()` (the SAME derivation the service-proxy uses, so
14
+ * there is never a port-selection problem and never a clash).
15
+ *
16
+ * ── Host selection is typed config, never an env toggle (ADR-0013) ─────────────
17
+ *
18
+ * `host` is a closed union (`'shared' | 'private'`) carried on
19
+ * `EmbeddingProviderConfig.host` and reported in `health()`. There is
20
+ * deliberately NO `SOX_EMBED_HOST=shared|private` variable: a behavior switch
21
+ * must be visible, validated, and auditable, not an ambient string. The only
22
+ * env reads here are ADR-0013 D3/D5 shapes:
23
+ *
24
+ * - `SOX_EMBED_HOST_IDLE_GRACE_MS` — a numeric tuning constant (D3): how long
25
+ * the host lingers after its last client leaves. Additive/numeric only.
26
+ * - `SOX_ECOSYSTEM_HOME` — host config (D5): where the socket lives.
27
+ * - `SOX_EMBED_HOST_MAIN` / `SOX_EMBED_HOST_SOCKET` — host-injected transport
28
+ * config (D5) / test seams; they select a path, they never enable a feature.
29
+ *
30
+ * Leaf module — node builtins only (fs, os, path, url, crypto, module) plus
31
+ * `backendSocketPath` from `@adhd/sox-service-proxy`.
32
+ */
33
+ import { existsSync } from 'node:fs';
34
+ import { createHash } from 'node:crypto';
35
+ import { createRequire } from 'node:module';
36
+ import { homedir } from 'node:os';
37
+ import { dirname, join } from 'node:path';
38
+ import { fileURLToPath } from 'node:url';
39
+ import { backendSocketPath } from '@adhd/sox-service-proxy';
40
+ const __dirname = dirname(fileURLToPath(import.meta.url));
41
+ /**
42
+ * Bumped whenever the host's wire protocol or behavior changes incompatibly.
43
+ *
44
+ * Open question #4 in SPEC-EMBEDDING-FUNNEL.md ("a running host is an old
45
+ * build") is resolved with this constant rather than the npm package version.
46
+ * Rationale: the real hazard is a host whose `embedding.*` contract the new
47
+ * consumer cannot speak — a *protocol* change — not every cosmetic patch. Keying
48
+ * on the npm version would spawn a brand-new host on every patch bump (briefly
49
+ * two hosts, defeating the funnel across an upgrade window) while the explicit
50
+ * protocol version forces a new socket exactly when compatibility actually
51
+ * breaks. Bump this with any change to the `embedding.*` method set, the payload
52
+ * shape, or the response shape in `embedHostMain.ts`.
53
+ */
54
+ export const EMBED_HOST_PROTOCOL_VERSION = 1;
55
+ /** Default grace before a zero-client host reaps itself. Sized to the short-lived-CLI arrival cadence. */
56
+ export const DEFAULT_EMBED_HOST_IDLE_GRACE_MS = 30_000;
57
+ /**
58
+ * Process-wide host-selection override. `null` ⇒ `'shared'`.
59
+ *
60
+ * Deliberately NOT an env var (ADR-0013): the typed
61
+ * `EmbeddingProviderConfig.host` field is applied here by
62
+ * `createEmbeddingProvider()` before the accessor singleton is constructed.
63
+ * Host selection is a process-wide posture — once a consumer has resolved its
64
+ * accessor, changing this does not retroactively re-point it (documented, not
65
+ * hidden).
66
+ */
67
+ let _hostOverride = null;
68
+ /**
69
+ * Apply the typed `host` field from an `EmbeddingProviderConfig`. Passing
70
+ * `undefined` leaves the current posture unchanged (so a `remote` provider
71
+ * without a `host` field never resets a deliberate `'private'` selection).
72
+ */
73
+ export function configureEmbedHostHost(host) {
74
+ if (host === undefined)
75
+ return;
76
+ if (host !== 'shared' && host !== 'private') {
77
+ throw new TypeError(`EmbedHostMode must be 'shared' or 'private', got ${String(host)}`);
78
+ }
79
+ _hostOverride = host;
80
+ }
81
+ /** TEST-ONLY: clear the process-wide host override back to the `'shared'` default. */
82
+ export function __resetEmbedHostConfigForTests() {
83
+ _hostOverride = null;
84
+ }
85
+ /**
86
+ * Resolve the funnel configuration. `host` defaults to `'shared'`; `idleGraceMs`
87
+ * is a numeric tuning constant (ADR-0013 D3) with a hard default.
88
+ */
89
+ export function resolveEmbedHostConfig() {
90
+ return {
91
+ host: _hostOverride ?? 'shared',
92
+ socketDir: resolveEmbedHostSocketDir(),
93
+ idleGraceMs: resolveEmbedHostIdleGraceMs(),
94
+ };
95
+ }
96
+ /**
97
+ * ADR-0013 D3 tuning constant: `SOX_EMBED_HOST_IDLE_GRACE_MS`. A non-positive or
98
+ * non-numeric value is rejected loudly (never silently treated as "off").
99
+ */
100
+ export function resolveEmbedHostIdleGraceMs() {
101
+ const raw = process.env['SOX_EMBED_HOST_IDLE_GRACE_MS'];
102
+ if (raw === undefined || raw === '')
103
+ return DEFAULT_EMBED_HOST_IDLE_GRACE_MS;
104
+ const parsed = Number(raw);
105
+ if (!Number.isFinite(parsed) || parsed <= 0) {
106
+ throw new TypeError(`SOX_EMBED_HOST_IDLE_GRACE_MS must be a positive number, got ${JSON.stringify(raw)}`);
107
+ }
108
+ return parsed;
109
+ }
110
+ /**
111
+ * ADR-0004 D5: the host socket lives under `$SOX_ECOSYSTEM_HOME/run` (the user
112
+ * data root's `run/` dir). Mirrors `@adhd/sox-host-runtime`'s `runDir()` without
113
+ * importing it — this package is a low-tier leaf and must not gain a
114
+ * host-runtime dependency. `SOX_ECOSYSTEM_HOME` defaults to `~/.adhd/sox-ecosystem`
115
+ * exactly as `data-paths.ts`'s `DATA_SUBDIR` does.
116
+ */
117
+ export function resolveEmbedHostSocketDir() {
118
+ const home = process.env['SOX_ECOSYSTEM_HOME'];
119
+ const root = home !== undefined && home !== '' ? home : join(homedir(), '.adhd', 'sox-ecosystem');
120
+ return join(root, 'run');
121
+ }
122
+ /**
123
+ * The machine-wide [def:singleton-key] for the host serving `(modelId, ep,
124
+ * cacheDir)`. Identical inputs ⇒ identical key ⇒ identical socket ⇒ one host,
125
+ * across every consumer process on the box.
126
+ *
127
+ * `cacheDirDigest` is a short sha256 of the ABSOLUTE cache dir, so two stores
128
+ * pointed at different model caches never collide onto one host. The protocol
129
+ * version is appended (see {@link EMBED_HOST_PROTOCOL_VERSION}).
130
+ */
131
+ export function embedHostSingletonKey(modelId, ep, cacheDir) {
132
+ const digest = createHash('sha256').update(cacheDir, 'utf8').digest('hex').slice(0, 12);
133
+ return `embedding-host:v${EMBED_HOST_PROTOCOL_VERSION}:${modelId}:${ep}:${digest}`;
134
+ }
135
+ /** Derive the host UDS path from the resolved config and singleton key. */
136
+ export function embedHostSocketPath(cfg, key) {
137
+ return backendSocketPath(cfg.socketDir, key);
138
+ }
139
+ /**
140
+ * Resolve the runnable host entrypoint to spawn.
141
+ *
142
+ * Order:
143
+ * 1. `SOX_EMBED_HOST_MAIN` (D5/test seam) — a path injection, never a feature
144
+ * toggle. Used by the funnel teeth suite to run the host from source via a
145
+ * tsx shim without a prior build.
146
+ * 2. A `__dirname` sibling (`dist/embedHostMain.js`) — the npm AND bundled
147
+ * case. The literal `join(__dirname, 'embedHostMain.js')` is load-bearing:
148
+ * `bundle-extension.cjs`'s `verifySidecarReferences()` scans emitted files
149
+ * for exactly this shape, so the sidecar can never ship missing (BL-259).
150
+ * 3. `src/../dist/embedHostMain.js` — vitest's `src/`-resident `__dirname`.
151
+ * 4. `require.resolve('@adhd/sox-embedding-provider/embed-host')` — the
152
+ * package `exports` subpath, when self-reference is available.
153
+ */
154
+ export function resolveEmbedHostMainPath() {
155
+ const override = process.env['SOX_EMBED_HOST_MAIN'];
156
+ if (override !== undefined && override !== '')
157
+ return override;
158
+ const sibling = join(__dirname, 'embedHostMain.js');
159
+ if (existsSync(sibling))
160
+ return sibling;
161
+ const distSibling = join(__dirname, '..', 'dist', 'embedHostMain.js');
162
+ if (existsSync(distSibling))
163
+ return distSibling;
164
+ try {
165
+ return createRequire(import.meta.url).resolve('@adhd/sox-embedding-provider/embed-host');
166
+ }
167
+ catch {
168
+ // Last resort: name the path that was actually attempted in any later error.
169
+ return sibling;
170
+ }
171
+ }
172
+ /**
173
+ * Where the detached host's stderr is redirected (its stdout/stdin are severed).
174
+ * Kept beside the socket so a wedged host's startup diagnostics are greppable
175
+ * without inheriting any caller fd ([inv:no-fd-inherit], BL-67).
176
+ */
177
+ export function resolveEmbedHostStderrLogPath(cfg) {
178
+ return join(cfg.socketDir, 'logs', 'embed-host.stderr.log');
179
+ }
180
+ //# sourceMappingURL=embedHostConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedHostConfig.js","sourceRoot":"","sources":["../src/embedHostConfig.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * embedHostMain.ts — the peer-spawned, self-reaping embedding host process
3
+ * (SPEC-EMBEDDING-FUNNEL.md §C).
4
+ *
5
+ * This is the compute backend of the funnel: a plain, DETACHED Node process,
6
+ * spawned on demand by the first consumer through `ensureBackend()`'s O_EXCL
7
+ * singleton spawn-lock. It is **never supervised** (no launchd/KeepAlive) and it
8
+ * **reaps itself** — a debounced, ref-counted teardown retires it
9
+ * `idleGraceMs` after the last cross-process client disconnects and in-flight
10
+ * work drains.
11
+ *
12
+ * ── Compute-only (ADR-0012) ────────────────────────────────────────────────────
13
+ *
14
+ * The host holds NO store connection. It forwards `embedding.*` payloads 1:1 to
15
+ * its private ONNX pool and never opens a database. It therefore cannot
16
+ * serialize store access and must never be described as single-writer or as a
17
+ * store serialization point; concurrent store writers are unaffected.
18
+ *
19
+ * ── No recursion ───────────────────────────────────────────────────────────────
20
+ *
21
+ * The handler forwards to `getPrivateFastembedProcess()` — the PRIVATE pool — and
22
+ * NEVER to `getSharedFastembedProcess()`, which under `host: 'shared'` would
23
+ * return a `FunneledFastembedClient` and dial this very host (infinite
24
+ * recursion). The import graph is arranged so that mistake is a type error, not
25
+ * a runtime hang.
26
+ *
27
+ * ── Teardown inputs are CROSS-PROCESS ─────────────────────────────────────────
28
+ *
29
+ * - `activeClients` — live UDS client connections, from `serveBackend`'s
30
+ * `onClientCountChange` hook (the cross-process half);
31
+ * - `privateClient.pendingCount` — this host's own in-flight requests (the
32
+ * in-process half).
33
+ *
34
+ * `activeClients === 0 && pendingCount === 0` arms the grace timer; a new client
35
+ * or request cancels it. On expiry the private pool is terminated, the listener
36
+ * closed (which unlinks the socket), and the process exits 0. The private pool's
37
+ * ONNX child is forked `detached: false`, so it dies with the host — no orphans.
38
+ */
39
+ /**
40
+ * Start the host: bind the UDS, serve `embedding.*`, and arm the debounced
41
+ * self-reap. Resolves once the listener is up (so a caller/test can await
42
+ * readiness); the process stays alive until the teardown fires or a signal
43
+ * arrives.
44
+ */
45
+ export declare function runEmbedHost(): Promise<void>;
46
+ //# sourceMappingURL=embedHostMain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedHostMain.d.ts","sourceRoot":"","sources":["../src/embedHostMain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAyBH;;;;;GAKG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CA2GlD"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * embedHostMain.ts — the peer-spawned, self-reaping embedding host process
3
+ * (SPEC-EMBEDDING-FUNNEL.md §C).
4
+ *
5
+ * This is the compute backend of the funnel: a plain, DETACHED Node process,
6
+ * spawned on demand by the first consumer through `ensureBackend()`'s O_EXCL
7
+ * singleton spawn-lock. It is **never supervised** (no launchd/KeepAlive) and it
8
+ * **reaps itself** — a debounced, ref-counted teardown retires it
9
+ * `idleGraceMs` after the last cross-process client disconnects and in-flight
10
+ * work drains.
11
+ *
12
+ * ── Compute-only (ADR-0012) ────────────────────────────────────────────────────
13
+ *
14
+ * The host holds NO store connection. It forwards `embedding.*` payloads 1:1 to
15
+ * its private ONNX pool and never opens a database. It therefore cannot
16
+ * serialize store access and must never be described as single-writer or as a
17
+ * store serialization point; concurrent store writers are unaffected.
18
+ *
19
+ * ── No recursion ───────────────────────────────────────────────────────────────
20
+ *
21
+ * The handler forwards to `getPrivateFastembedProcess()` — the PRIVATE pool — and
22
+ * NEVER to `getSharedFastembedProcess()`, which under `host: 'shared'` would
23
+ * return a `FunneledFastembedClient` and dial this very host (infinite
24
+ * recursion). The import graph is arranged so that mistake is a type error, not
25
+ * a runtime hang.
26
+ *
27
+ * ── Teardown inputs are CROSS-PROCESS ─────────────────────────────────────────
28
+ *
29
+ * - `activeClients` — live UDS client connections, from `serveBackend`'s
30
+ * `onClientCountChange` hook (the cross-process half);
31
+ * - `privateClient.pendingCount` — this host's own in-flight requests (the
32
+ * in-process half).
33
+ *
34
+ * `activeClients === 0 && pendingCount === 0` arms the grace timer; a new client
35
+ * or request cancels it. On expiry the private pool is terminated, the listener
36
+ * closed (which unlinks the socket), and the process exits 0. The private pool's
37
+ * ONNX child is forked `detached: false`, so it dies with the host — no orphans.
38
+ */
39
+ import { fileURLToPath } from 'node:url';
40
+ import { resolve } from 'node:path';
41
+ import { serveBackend } from '@adhd/sox-service-proxy';
42
+ import { resolveEmbedHostIdleGraceMs } from './embedHostConfig.js';
43
+ import { getPrivateFastembedProcess, resetPrivateFastembedProcess } from './sharedFastembedProcess.js';
44
+ /** The `embedding.*` methods the host serves. */
45
+ const HOST_METHODS = new Set([
46
+ 'embedding.init',
47
+ 'embedding.embed',
48
+ 'embedding.embedBatch',
49
+ 'embedding.reset',
50
+ 'embedding.health',
51
+ ]);
52
+ function ok(id, result) {
53
+ return { jsonrpc: '2.0', id: id ?? null, result };
54
+ }
55
+ function fail(id, code, message) {
56
+ return { jsonrpc: '2.0', id: id ?? null, error: { code, message } };
57
+ }
58
+ /**
59
+ * Start the host: bind the UDS, serve `embedding.*`, and arm the debounced
60
+ * self-reap. Resolves once the listener is up (so a caller/test can await
61
+ * readiness); the process stays alive until the teardown fires or a signal
62
+ * arrives.
63
+ */
64
+ export async function runEmbedHost() {
65
+ const socketPath = process.env['SOX_EMBED_HOST_SOCKET'];
66
+ if (!socketPath) {
67
+ process.stderr.write('[embed-host] SOX_EMBED_HOST_SOCKET is not set — the host is spawned by the funnel client, not run directly.\n');
68
+ process.exit(2);
69
+ }
70
+ const idleGraceMs = resolveEmbedHostIdleGraceMs();
71
+ const privateClient = getPrivateFastembedProcess();
72
+ let activeClients = 0;
73
+ let idleTimer = null;
74
+ let shuttingDown = false;
75
+ let handle = null;
76
+ const cancelIdle = () => {
77
+ if (idleTimer) {
78
+ clearTimeout(idleTimer);
79
+ idleTimer = null;
80
+ }
81
+ };
82
+ const teardown = async () => {
83
+ if (shuttingDown)
84
+ return;
85
+ shuttingDown = true;
86
+ cancelIdle();
87
+ try {
88
+ await privateClient.terminate();
89
+ }
90
+ catch {
91
+ /* best-effort — the ONNX child dies with us regardless (detached:false) */
92
+ }
93
+ try {
94
+ await handle?.close();
95
+ }
96
+ catch {
97
+ /* best-effort — the socket unlink happens inside close() */
98
+ }
99
+ process.exit(0);
100
+ };
101
+ const armIfIdle = () => {
102
+ if (shuttingDown || idleTimer)
103
+ return;
104
+ if (activeClients !== 0 || privateClient.pendingCount !== 0)
105
+ return;
106
+ idleTimer = setTimeout(() => {
107
+ idleTimer = null;
108
+ void teardown();
109
+ }, idleGraceMs);
110
+ // The listener keeps the loop alive; the timer itself must not.
111
+ idleTimer.unref?.();
112
+ };
113
+ const handler = async (req) => {
114
+ // Any inbound request is demand — cancel a pending reap.
115
+ cancelIdle();
116
+ const id = req.id;
117
+ const method = req.method;
118
+ if (!HOST_METHODS.has(method)) {
119
+ return fail(id, -32601, `method not found: ${method}`);
120
+ }
121
+ try {
122
+ if (method === 'embedding.health') {
123
+ return ok(id, {
124
+ started: privateClient.started,
125
+ pendingCount: privateClient.pendingCount,
126
+ activeClients,
127
+ idleGraceMs,
128
+ });
129
+ }
130
+ if (method === 'embedding.reset') {
131
+ await resetPrivateFastembedProcess();
132
+ return ok(id, { reset: true });
133
+ }
134
+ // embedding.init | embedding.embed | embedding.embedBatch — forward the
135
+ // payload 1:1 to the PRIVATE pool (never the funnel accessor).
136
+ const params = (req.params ?? {});
137
+ const result = await privateClient.request(params);
138
+ return ok(id, result);
139
+ }
140
+ catch (e) {
141
+ return fail(id, -32603, e instanceof Error ? e.message : String(e));
142
+ }
143
+ finally {
144
+ // A request may have drained the last in-flight work with no clients
145
+ // attached (e.g. a one-shot embed) — re-arm the reap.
146
+ if (activeClients === 0)
147
+ armIfIdle();
148
+ }
149
+ };
150
+ handle = await serveBackend({
151
+ socketPath,
152
+ handler,
153
+ onDiagnostic: (line) => process.stderr.write(line + '\n'),
154
+ onClientCountChange: (active) => {
155
+ activeClients = active;
156
+ if (active > 0)
157
+ cancelIdle();
158
+ else
159
+ armIfIdle();
160
+ },
161
+ });
162
+ // Arm immediately: if no client ever connects (e.g. the spawner died between
163
+ // spawn and dial), the host must still reap rather than linger forever.
164
+ armIfIdle();
165
+ // A detached host can still be signalled directly (kill, OS teardown).
166
+ process.on('SIGTERM', () => void teardown());
167
+ process.on('SIGINT', () => void teardown());
168
+ }
169
+ /**
170
+ * True when this module is the process entrypoint (`node dist/embedHostMain.js`).
171
+ * `ensureBackend` spawns exactly that. A test shim that imports this module and
172
+ * calls `runEmbedHost()` explicitly is NOT the entrypoint, so it does not
173
+ * double-start.
174
+ */
175
+ function isEntrypoint() {
176
+ const argv1 = process.argv[1];
177
+ if (!argv1)
178
+ return false;
179
+ try {
180
+ return resolve(fileURLToPath(import.meta.url)) === resolve(argv1);
181
+ }
182
+ catch {
183
+ return false;
184
+ }
185
+ }
186
+ if (isEntrypoint()) {
187
+ runEmbedHost().catch((err) => {
188
+ process.stderr.write(`[embed-host] fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`);
189
+ process.exit(1);
190
+ });
191
+ }
192
+ //# sourceMappingURL=embedHostMain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedHostMain.js","sourceRoot":"","sources":["../src/embedHostMain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAiE,MAAM,yBAAyB,CAAC;AACtH,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,MAAM,6BAA6B,CAAC;AAEvG,iDAAiD;AACjD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC3B,gBAAgB;IAChB,iBAAiB;IACjB,sBAAsB;IACtB,iBAAiB;IACjB,kBAAkB;CACnB,CAAC,CAAC;AAEH,SAAS,EAAE,CAAC,EAAwB,EAAE,MAAe;IACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;AACpD,CAAC;AAED,SAAS,IAAI,CAAC,EAAwB,EAAE,IAAY,EAAE,OAAe;IACnE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;AACtE,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,+GAA+G,CAChH,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,WAAW,GAAG,2BAA2B,EAAE,CAAC;IAClD,MAAM,aAAa,GAAG,0BAA0B,EAAE,CAAC;IAEnD,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,SAAS,GAA0B,IAAI,CAAC;IAC5C,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,MAAM,GAAyB,IAAI,CAAC;IAExC,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,IAAI,SAAS,EAAE,CAAC;YACd,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,IAAmB,EAAE;QACzC,IAAI,YAAY;YAAE,OAAO;QACzB,YAAY,GAAG,IAAI,CAAC;QACpB,UAAU,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,SAAS,EAAE,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,2EAA2E;QAC7E,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,4DAA4D;QAC9D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,GAAS,EAAE;QAC3B,IAAI,YAAY,IAAI,SAAS;YAAE,OAAO;QACtC,IAAI,aAAa,KAAK,CAAC,IAAI,aAAa,CAAC,YAAY,KAAK,CAAC;YAAE,OAAO;QACpE,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAC1B,SAAS,GAAG,IAAI,CAAC;YACjB,KAAK,QAAQ,EAAE,CAAC;QAClB,CAAC,EAAE,WAAW,CAAC,CAAC;QAChB,gEAAgE;QAChE,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;IACtB,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,KAAK,EAAE,GAAmB,EAA4B,EAAE;QACtE,yDAAyD;QACzD,UAAU,EAAE,CAAC;QACb,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QAE1B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,qBAAqB,MAAM,EAAE,CAAC,CAAC;QACzD,CAAC;QAED,IAAI,CAAC;YACH,IAAI,MAAM,KAAK,kBAAkB,EAAE,CAAC;gBAClC,OAAO,EAAE,CAAC,EAAE,EAAE;oBACZ,OAAO,EAAE,aAAa,CAAC,OAAO;oBAC9B,YAAY,EAAE,aAAa,CAAC,YAAY;oBACxC,aAAa;oBACb,WAAW;iBACZ,CAAC,CAAC;YACL,CAAC;YACD,IAAI,MAAM,KAAK,iBAAiB,EAAE,CAAC;gBACjC,MAAM,4BAA4B,EAAE,CAAC;gBACrC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,CAAC;YACD,wEAAwE;YACxE,+DAA+D;YAC/D,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;YAC7D,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YACnD,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACxB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACtE,CAAC;gBAAS,CAAC;YACT,qEAAqE;YACrE,sDAAsD;YACtD,IAAI,aAAa,KAAK,CAAC;gBAAE,SAAS,EAAE,CAAC;QACvC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,GAAG,MAAM,YAAY,CAAC;QAC1B,UAAU;QACV,OAAO;QACP,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;QACzD,mBAAmB,EAAE,CAAC,MAAM,EAAE,EAAE;YAC9B,aAAa,GAAG,MAAM,CAAC;YACvB,IAAI,MAAM,GAAG,CAAC;gBAAE,UAAU,EAAE,CAAC;;gBACxB,SAAS,EAAE,CAAC;QACnB,CAAC;KACF,CAAC,CAAC;IAEH,6EAA6E;IAC7E,wEAAwE;IACxE,SAAS,EAAE,CAAC;IAEZ,uEAAuE;IACvE,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;IAC7C,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY;IACnB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,YAAY,EAAE,EAAE,CAAC;IACnB,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACpC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/G,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * errors.ts — the embedding error taxonomy, extracted so internal modules
3
+ * (notably `funnelClient.ts`) can throw typed errors without importing the
4
+ * public `index.ts` barrel and creating an import cycle.
5
+ *
6
+ * The classes are re-exported verbatim from `index.ts`, so the public surface is
7
+ * unchanged: `import { TransientEmbeddingError } from '@adhd/sox-embedding-provider'`
8
+ * keeps working, and `instanceof` identity is preserved (one class, one home).
9
+ *
10
+ * Three tiers, no silent degradation:
11
+ * - TransientEmbeddingError — the caller may retry (has `retryAfterMs`).
12
+ * - PermanentEmbeddingError — the caller must not retry.
13
+ * - ResolutionError — factory-time only (bad config / unknown model), never mid-call.
14
+ */
15
+ export declare class TransientEmbeddingError extends Error {
16
+ readonly retryAfterMs: number | undefined;
17
+ constructor(message: string, retryAfterMs?: number);
18
+ }
19
+ export declare class PermanentEmbeddingError extends Error {
20
+ constructor(message: string);
21
+ }
22
+ export declare class ResolutionError extends Error {
23
+ constructor(message: string);
24
+ }
25
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;gBAC9B,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;CAKnD;AAED,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B"}
package/dist/errors.js ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * errors.ts — the embedding error taxonomy, extracted so internal modules
3
+ * (notably `funnelClient.ts`) can throw typed errors without importing the
4
+ * public `index.ts` barrel and creating an import cycle.
5
+ *
6
+ * The classes are re-exported verbatim from `index.ts`, so the public surface is
7
+ * unchanged: `import { TransientEmbeddingError } from '@adhd/sox-embedding-provider'`
8
+ * keeps working, and `instanceof` identity is preserved (one class, one home).
9
+ *
10
+ * Three tiers, no silent degradation:
11
+ * - TransientEmbeddingError — the caller may retry (has `retryAfterMs`).
12
+ * - PermanentEmbeddingError — the caller must not retry.
13
+ * - ResolutionError — factory-time only (bad config / unknown model), never mid-call.
14
+ */
15
+ export class TransientEmbeddingError extends Error {
16
+ retryAfterMs;
17
+ constructor(message, retryAfterMs) {
18
+ super(message);
19
+ this.name = 'TransientEmbeddingError';
20
+ this.retryAfterMs = retryAfterMs;
21
+ }
22
+ }
23
+ export class PermanentEmbeddingError extends Error {
24
+ constructor(message) {
25
+ super(message);
26
+ this.name = 'PermanentEmbeddingError';
27
+ }
28
+ }
29
+ export class ResolutionError extends Error {
30
+ constructor(message) {
31
+ super(message);
32
+ this.name = 'ResolutionError';
33
+ }
34
+ }
35
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IACvC,YAAY,CAAqB;IAC1C,YAAY,OAAe,EAAE,YAAqB;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;CACF;AAED,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"fastembed.d.ts","sourceRoot":"","sources":["../src/fastembed.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpG,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAO3G,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAgBrD,0DAA0D;AAC1D,QAAA,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEtC,CAAC;AAEF,gEAAgE;AAChE,QAAA,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAE5C,CAAC;AAEF,QAAA,MAAM,aAAa,qBAAqB,CAAC;AACzC,QAAA,MAAM,kBAAkB,MAAM,CAAC;AAE/B;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,iBAAiB;IACzD,QAAQ,CAAC,QAAQ,EAAE,yBAAyB,CAAC;IAC7C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IASzB,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,kBAAkB,CAAiB;IAE3C;;;;;OAKG;gBAED,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,GAAE,qBAAmD;IAkBnE,MAAM,IAAI,eAAe;IAmBnB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;IAkBlE,UAAU,CACf,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC9C,aAAa,CAAC,YAAY,CAAC;IAuBxB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C;;;OAGG;IACH,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACH,OAAO,CAAC,SAAS;IAmBjB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IA0BhB;;;OAGG;IACH,OAAO,CAAC,WAAW;YAQL,SAAS;YA2CT,SAAS;IAKvB,OAAO,CAAC,mBAAmB;CAc5B;AAED,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"fastembed.d.ts","sourceRoot":"","sources":["../src/fastembed.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,KAAK,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEpG,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAO3G,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAgBrD,0DAA0D;AAC1D,QAAA,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEtC,CAAC;AAEF,gEAAgE;AAChE,QAAA,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAE5C,CAAC;AAEF,QAAA,MAAM,aAAa,qBAAqB,CAAC;AACzC,QAAA,MAAM,kBAAkB,MAAM,CAAC;AAE/B;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,iBAAiB;IACzD,QAAQ,CAAC,QAAQ,EAAE,yBAAyB,CAAC;IAC7C,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,QAAQ,CAAS;IASzB,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,kBAAkB,CAAiB;IAE3C;;;;;OAKG;gBAED,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,YAAY,GAAE,qBAAmD;IAkBnE,MAAM,IAAI,eAAe;IAqBnB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;IAkBlE,UAAU,CACf,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,SAAS,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAC9C,aAAa,CAAC,YAAY,CAAC;IAuBxB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAO5C;;;OAGG;IACH,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACH,OAAO,CAAC,SAAS;IAmBjB;;;OAGG;IACH,OAAO,CAAC,QAAQ;IA0BhB;;;OAGG;IACH,OAAO,CAAC,WAAW;YAQL,SAAS;YA2CT,SAAS;IAKvB,OAAO,CAAC,mBAAmB;CAc5B;AAED,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,kBAAkB,EAAE,CAAC"}