@danielsimonjr/memoryjs 2.7.0 → 2.8.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/dist/cli/index.js +53 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +78 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +78 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -8480,10 +8480,13 @@ interface TaskSubmitOptions {
|
|
|
8480
8480
|
}
|
|
8481
8481
|
/**
|
|
8482
8482
|
* Handle returned by `submitWithHandle`. The `result` promise settles when
|
|
8483
|
-
* the task finishes; `cancel()`
|
|
8484
|
-
*
|
|
8485
|
-
*
|
|
8486
|
-
*
|
|
8483
|
+
* the task finishes; `cancel()` performs two-tier cancellation:
|
|
8484
|
+
*
|
|
8485
|
+
* - If still pending in the queue: evict cleanly. Returns `true`.
|
|
8486
|
+
* - If already dispatched: propagate to the underlying
|
|
8487
|
+
* `WorkerpoolPromise.cancel()` so the running worker rejects with
|
|
8488
|
+
* `CancellationError`. Returns `true` if the workerpool promise was
|
|
8489
|
+
* still pending at the moment of cancel; `false` if it already settled.
|
|
8487
8490
|
*/
|
|
8488
8491
|
interface TaskHandle<R> {
|
|
8489
8492
|
id: string;
|
|
@@ -8534,6 +8537,7 @@ declare class WorkerTaskManager {
|
|
|
8534
8537
|
private readonly touchedPoolIds;
|
|
8535
8538
|
private readonly cancelledTaskIds;
|
|
8536
8539
|
private readonly handleStatus;
|
|
8540
|
+
private readonly liveExecPromises;
|
|
8537
8541
|
constructor(opts?: {
|
|
8538
8542
|
/** Max concurrent tasks across the queue. Default: cpus − 1. */
|
|
8539
8543
|
concurrency?: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -8480,10 +8480,13 @@ interface TaskSubmitOptions {
|
|
|
8480
8480
|
}
|
|
8481
8481
|
/**
|
|
8482
8482
|
* Handle returned by `submitWithHandle`. The `result` promise settles when
|
|
8483
|
-
* the task finishes; `cancel()`
|
|
8484
|
-
*
|
|
8485
|
-
*
|
|
8486
|
-
*
|
|
8483
|
+
* the task finishes; `cancel()` performs two-tier cancellation:
|
|
8484
|
+
*
|
|
8485
|
+
* - If still pending in the queue: evict cleanly. Returns `true`.
|
|
8486
|
+
* - If already dispatched: propagate to the underlying
|
|
8487
|
+
* `WorkerpoolPromise.cancel()` so the running worker rejects with
|
|
8488
|
+
* `CancellationError`. Returns `true` if the workerpool promise was
|
|
8489
|
+
* still pending at the moment of cancel; `false` if it already settled.
|
|
8487
8490
|
*/
|
|
8488
8491
|
interface TaskHandle<R> {
|
|
8489
8492
|
id: string;
|
|
@@ -8534,6 +8537,7 @@ declare class WorkerTaskManager {
|
|
|
8534
8537
|
private readonly touchedPoolIds;
|
|
8535
8538
|
private readonly cancelledTaskIds;
|
|
8536
8539
|
private readonly handleStatus;
|
|
8540
|
+
private readonly liveExecPromises;
|
|
8537
8541
|
constructor(opts?: {
|
|
8538
8542
|
/** Max concurrent tasks across the queue. Default: cpus − 1. */
|
|
8539
8543
|
concurrency?: number;
|
package/dist/index.js
CHANGED
|
@@ -3441,6 +3441,10 @@ var init_WorkerTaskManager = __esm({
|
|
|
3441
3441
|
touchedPoolIds = /* @__PURE__ */ new Set();
|
|
3442
3442
|
cancelledTaskIds = /* @__PURE__ */ new Set();
|
|
3443
3443
|
handleStatus = /* @__PURE__ */ new Map();
|
|
3444
|
+
// Live `pool.exec(...)` promises by task id. Populated when a task starts
|
|
3445
|
+
// running so the handle can call `.cancel()` on the workerpool promise
|
|
3446
|
+
// for mid-execution cancellation. Cleared on completion / failure.
|
|
3447
|
+
liveExecPromises = /* @__PURE__ */ new Map();
|
|
3444
3448
|
constructor(opts = {}) {
|
|
3445
3449
|
this.queue = new TaskQueue({
|
|
3446
3450
|
concurrency: opts.concurrency,
|
|
@@ -3480,7 +3484,13 @@ var init_WorkerTaskManager = __esm({
|
|
|
3480
3484
|
this.handleStatus.set(id, "running" /* RUNNING */);
|
|
3481
3485
|
const pool = this.poolManager.getPool(input.workerType, opts.poolConfig);
|
|
3482
3486
|
this.touchedPoolIds.add(input.workerType);
|
|
3483
|
-
|
|
3487
|
+
const execPromise = pool.exec(input.methodName, input.args);
|
|
3488
|
+
this.liveExecPromises.set(id, execPromise);
|
|
3489
|
+
try {
|
|
3490
|
+
return await execPromise;
|
|
3491
|
+
} finally {
|
|
3492
|
+
this.liveExecPromises.delete(id);
|
|
3493
|
+
}
|
|
3484
3494
|
}
|
|
3485
3495
|
};
|
|
3486
3496
|
const result = this.queue.enqueue(task).then(async (res) => {
|
|
@@ -3502,8 +3512,21 @@ var init_WorkerTaskManager = __esm({
|
|
|
3502
3512
|
const evicted = this.queue.cancel(id);
|
|
3503
3513
|
if (evicted) {
|
|
3504
3514
|
this.handleStatus.set(id, "cancelled" /* CANCELLED */);
|
|
3515
|
+
return true;
|
|
3505
3516
|
}
|
|
3506
|
-
|
|
3517
|
+
const live = this.liveExecPromises.get(id);
|
|
3518
|
+
if (live && typeof live.cancel === "function") {
|
|
3519
|
+
if (live.pending === false) return false;
|
|
3520
|
+
try {
|
|
3521
|
+
live.cancel();
|
|
3522
|
+
this.handleStatus.set(id, "cancelled" /* CANCELLED */);
|
|
3523
|
+
return true;
|
|
3524
|
+
} catch (e) {
|
|
3525
|
+
logger.warn(`[WorkerTaskManager] cancel() on live exec for ${id} threw:`, e);
|
|
3526
|
+
return false;
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
return false;
|
|
3507
3530
|
},
|
|
3508
3531
|
status: () => this.handleStatus.get(id) ?? "pending" /* PENDING */
|
|
3509
3532
|
};
|
|
@@ -20844,6 +20867,27 @@ CREATE INDEX IF NOT EXISTS idx_entities_project_id ON entities(project_id);
|
|
|
20844
20867
|
CREATE INDEX IF NOT EXISTS idx_entities_content_hash ON entities(content_hash);
|
|
20845
20868
|
CREATE INDEX IF NOT EXISTS idx_entities_tags_gin ON entities USING GIN(tags);
|
|
20846
20869
|
|
|
20870
|
+
-- v2.8.0 \u2014 generated tsvector column for full-text search.
|
|
20871
|
+
-- name is weighted A (highest), observations B, tags C. PostgreSQL 12+
|
|
20872
|
+
-- supports GENERATED ALWAYS AS ... STORED; the DO block makes the column
|
|
20873
|
+
-- add idempotent on older + newer servers without requiring CREATE OR
|
|
20874
|
+
-- REPLACE semantics on ALTER.
|
|
20875
|
+
DO $$ BEGIN
|
|
20876
|
+
IF NOT EXISTS (
|
|
20877
|
+
SELECT 1 FROM information_schema.columns
|
|
20878
|
+
WHERE table_name = 'entities' AND column_name = 'fts_vector'
|
|
20879
|
+
) THEN
|
|
20880
|
+
ALTER TABLE entities ADD COLUMN fts_vector tsvector
|
|
20881
|
+
GENERATED ALWAYS AS (
|
|
20882
|
+
setweight(to_tsvector('english', name), 'A') ||
|
|
20883
|
+
setweight(to_tsvector('english', coalesce(array_to_string(observations, ' '), '')), 'B') ||
|
|
20884
|
+
setweight(to_tsvector('english', coalesce(array_to_string(tags, ' '), '')), 'C')
|
|
20885
|
+
) STORED;
|
|
20886
|
+
END IF;
|
|
20887
|
+
END $$;
|
|
20888
|
+
|
|
20889
|
+
CREATE INDEX IF NOT EXISTS idx_entities_fts_gin ON entities USING GIN(fts_vector);
|
|
20890
|
+
|
|
20847
20891
|
CREATE TABLE IF NOT EXISTS relations (
|
|
20848
20892
|
from_name TEXT NOT NULL,
|
|
20849
20893
|
to_name TEXT NOT NULL,
|
|
@@ -21163,6 +21207,38 @@ var PostgreSQLStorage = class {
|
|
|
21163
21207
|
hasRelations(entityName) {
|
|
21164
21208
|
return (this.outgoingRelations.get(entityName)?.length ?? 0) + (this.incomingRelations.get(entityName)?.length ?? 0) > 0;
|
|
21165
21209
|
}
|
|
21210
|
+
// ==================== Full-text search ====================
|
|
21211
|
+
/**
|
|
21212
|
+
* tsvector-backed full-text search. Uses `plainto_tsquery` so the input is
|
|
21213
|
+
* free-form (no boolean operator syntax required); ranks via `ts_rank` on
|
|
21214
|
+
* the weighted `fts_vector` column (name × A, observations × B, tags × C).
|
|
21215
|
+
*
|
|
21216
|
+
* Results are ordered by descending score and capped at `options.limit`
|
|
21217
|
+
* (default 50). Empty / whitespace-only queries return `[]` without
|
|
21218
|
+
* issuing a SQL call.
|
|
21219
|
+
*
|
|
21220
|
+
* @example
|
|
21221
|
+
* ```typescript
|
|
21222
|
+
* const matches = await storage.fullTextSearch('authentication flow', { limit: 10 });
|
|
21223
|
+
* // → [{ name: 'AuthService', score: 0.62 }, ...]
|
|
21224
|
+
* ```
|
|
21225
|
+
*/
|
|
21226
|
+
async fullTextSearch(query, options = {}) {
|
|
21227
|
+
const trimmed = query.trim();
|
|
21228
|
+
if (trimmed.length === 0) return [];
|
|
21229
|
+
await this.initSchema();
|
|
21230
|
+
const pool = await this.getPool();
|
|
21231
|
+
const limit = options.limit ?? 50;
|
|
21232
|
+
const res = await pool.query(
|
|
21233
|
+
`SELECT name, ts_rank(fts_vector, plainto_tsquery('english', $1))::float AS score
|
|
21234
|
+
FROM entities
|
|
21235
|
+
WHERE fts_vector @@ plainto_tsquery('english', $1)
|
|
21236
|
+
ORDER BY score DESC
|
|
21237
|
+
LIMIT $2`,
|
|
21238
|
+
[trimmed, limit]
|
|
21239
|
+
);
|
|
21240
|
+
return res.rows.map((r) => ({ name: r.name, score: Number(r.score) }));
|
|
21241
|
+
}
|
|
21166
21242
|
// ==================== Utility ====================
|
|
21167
21243
|
getFilePath() {
|
|
21168
21244
|
return this.connectionString;
|