@eidentic/postgres 0.1.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.
- package/LICENSE +201 -0
- package/README.md +42 -0
- package/dist/index.cjs +788 -0
- package/dist/index.d.cts +126 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.js +767 -0
- package/package.json +68 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { StorePort, GraphPort, DurablePort, SessionRecord, StoredEvent, Scope, MemoryBlock, BlockHistoryEntry, MemorySnippet, AssertFactInput, Fact, FactQuery, Checkpoint, IdempotencyRecord, SuspendDecision } from '@eidentic/types';
|
|
2
|
+
|
|
3
|
+
/** Minimal client surface satisfied by both `pg.Pool` and `@electric-sql/pglite`. */
|
|
4
|
+
interface PgClient {
|
|
5
|
+
/**
|
|
6
|
+
* Execute a parameterised query.
|
|
7
|
+
*
|
|
8
|
+
* Supply a row type parameter `R` to get compile-time column checking:
|
|
9
|
+
* ```ts
|
|
10
|
+
* const { rows } = await client.query<{ id: string; name: string }>(
|
|
11
|
+
* "SELECT id, name FROM users WHERE id = $1", [userId],
|
|
12
|
+
* );
|
|
13
|
+
* // rows is { id: string; name: string }[]
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The default is `any` for back-compat — untyped callers continue to work
|
|
17
|
+
* without changes, while new call-sites can opt in to typed rows.
|
|
18
|
+
*/
|
|
19
|
+
query<R = any>(text: string, params?: unknown[]): Promise<{
|
|
20
|
+
rows: R[];
|
|
21
|
+
}>;
|
|
22
|
+
/** Present on `pg.Pool` and `pg.Client`; absent on pglite. */
|
|
23
|
+
connect?(): Promise<PgPoolClient>;
|
|
24
|
+
}
|
|
25
|
+
/** Minimal surface of the dedicated client checked out from a `pg.Pool`. */
|
|
26
|
+
interface PgPoolClient {
|
|
27
|
+
/** @see {@link PgClient.query} */
|
|
28
|
+
query<R = any>(text: string, params?: unknown[]): Promise<{
|
|
29
|
+
rows: R[];
|
|
30
|
+
}>;
|
|
31
|
+
release(): void;
|
|
32
|
+
}
|
|
33
|
+
declare class PostgresStore implements StorePort, GraphPort, DurablePort {
|
|
34
|
+
private readonly client;
|
|
35
|
+
private factIdCounter;
|
|
36
|
+
private readonly newFactId;
|
|
37
|
+
private readonly graphNow;
|
|
38
|
+
/**
|
|
39
|
+
* Construct a PostgresStore wrapping an injected `PgClient`.
|
|
40
|
+
*
|
|
41
|
+
* Pass a `pg.Pool` or a `@electric-sql/pglite` instance as `client`.
|
|
42
|
+
* Note: when using `pg.Pool`, pass a dedicated client or pool — the store
|
|
43
|
+
* issues its own BEGIN/COMMIT on the connection for multi-statement atomicity.
|
|
44
|
+
* For pglite (single-connection WASM), BEGIN/COMMIT on the same client is fine.
|
|
45
|
+
*
|
|
46
|
+
* Call `await store.migrate()` before use, or use `PostgresStore.create()`
|
|
47
|
+
* which runs migrations automatically.
|
|
48
|
+
*/
|
|
49
|
+
constructor(client: PgClient, opts?: {
|
|
50
|
+
newId?: () => string;
|
|
51
|
+
now?: () => string;
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Create a PostgresStore and run migrations in one step.
|
|
55
|
+
* Convenience wrapper for `new PostgresStore(client)` + `migrate()`.
|
|
56
|
+
*/
|
|
57
|
+
static create(opts: {
|
|
58
|
+
client: PgClient;
|
|
59
|
+
newId?: () => string;
|
|
60
|
+
now?: () => string;
|
|
61
|
+
}): Promise<PostgresStore>;
|
|
62
|
+
migrate(): Promise<void>;
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Run `fn` inside a single Postgres transaction.
|
|
66
|
+
*
|
|
67
|
+
* When `this.client` is a `pg.Pool` (has a `connect()` method), we check out
|
|
68
|
+
* a dedicated connection so that BEGIN / body / COMMIT all execute on the same
|
|
69
|
+
* underlying socket — Pool.query() would otherwise dispatch each call to a
|
|
70
|
+
* different pooled connection, destroying atomicity.
|
|
71
|
+
*
|
|
72
|
+
* When `this.client` is pglite (no `connect()`), the client IS the connection;
|
|
73
|
+
* we issue BEGIN/COMMIT directly on it, matching the previous behaviour.
|
|
74
|
+
*/
|
|
75
|
+
private withTransaction;
|
|
76
|
+
createSession(s: SessionRecord): Promise<void>;
|
|
77
|
+
getSession(id: string): Promise<SessionRecord | null>;
|
|
78
|
+
appendEvents(events: StoredEvent[]): Promise<void>;
|
|
79
|
+
readEvents(sessionId: string): Promise<StoredEvent[]>;
|
|
80
|
+
getBlocks(scope: Scope): Promise<MemoryBlock[]>;
|
|
81
|
+
getBlock(scope: Scope, label: string): Promise<MemoryBlock | null>;
|
|
82
|
+
upsertBlock(scope: Scope, block: {
|
|
83
|
+
label: string;
|
|
84
|
+
value: string;
|
|
85
|
+
}, expectVersion?: number): Promise<MemoryBlock>;
|
|
86
|
+
appendBlock(scope: Scope, label: string, text: string): Promise<MemoryBlock>;
|
|
87
|
+
getBlockHistory(scope: Scope, label: string): Promise<BlockHistoryEntry[]>;
|
|
88
|
+
private writeBlock;
|
|
89
|
+
indexMemory(entries: Array<{
|
|
90
|
+
scope: Scope;
|
|
91
|
+
id: string;
|
|
92
|
+
text: string;
|
|
93
|
+
ingestedAt?: number;
|
|
94
|
+
metadata?: Record<string, unknown>;
|
|
95
|
+
}>): Promise<void>;
|
|
96
|
+
searchMemory(scope: Scope, query: string, topK: number): Promise<MemorySnippet[]>;
|
|
97
|
+
private rowToFact;
|
|
98
|
+
assertFact(scope: Scope, input: AssertFactInput): Promise<{
|
|
99
|
+
asserted: Fact;
|
|
100
|
+
invalidated: Fact[];
|
|
101
|
+
}>;
|
|
102
|
+
factHistory(scope: Scope, subject: string, predicate: string): Promise<Fact[]>;
|
|
103
|
+
corroborate(scope: Scope, factId: string, at?: number): Promise<number>;
|
|
104
|
+
expireFacts(scope: Scope, ids: string[], at: string): Promise<number>;
|
|
105
|
+
queryFacts(query: FactQuery): Promise<Fact[]>;
|
|
106
|
+
sweepExpired(scope: Scope, now: string): Promise<number>;
|
|
107
|
+
listSessions(opts?: {
|
|
108
|
+
agentId?: string;
|
|
109
|
+
limit?: number;
|
|
110
|
+
userId?: string;
|
|
111
|
+
orgId?: string;
|
|
112
|
+
}): Promise<SessionRecord[]>;
|
|
113
|
+
listBlocks(scope: Scope): Promise<MemoryBlock[]>;
|
|
114
|
+
eraseScope(scope: Scope): Promise<{
|
|
115
|
+
deleted: number;
|
|
116
|
+
}>;
|
|
117
|
+
writeCheckpoint(sessionId: string, seq: number, hash: string): Promise<void>;
|
|
118
|
+
lastCheckpoint(sessionId: string): Promise<Checkpoint | null>;
|
|
119
|
+
recordIntent(key: string, argsHash: string): Promise<void>;
|
|
120
|
+
recordCompletion(key: string, result: unknown): Promise<void>;
|
|
121
|
+
getIdempotency(key: string): Promise<IdempotencyRecord | null>;
|
|
122
|
+
recordDecision(sessionId: string, callId: string, decision: SuspendDecision): Promise<void>;
|
|
123
|
+
getDecision(sessionId: string, callId: string): Promise<SuspendDecision | null>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { type PgClient, type PgPoolClient, PostgresStore };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { StorePort, GraphPort, DurablePort, SessionRecord, StoredEvent, Scope, MemoryBlock, BlockHistoryEntry, MemorySnippet, AssertFactInput, Fact, FactQuery, Checkpoint, IdempotencyRecord, SuspendDecision } from '@eidentic/types';
|
|
2
|
+
|
|
3
|
+
/** Minimal client surface satisfied by both `pg.Pool` and `@electric-sql/pglite`. */
|
|
4
|
+
interface PgClient {
|
|
5
|
+
/**
|
|
6
|
+
* Execute a parameterised query.
|
|
7
|
+
*
|
|
8
|
+
* Supply a row type parameter `R` to get compile-time column checking:
|
|
9
|
+
* ```ts
|
|
10
|
+
* const { rows } = await client.query<{ id: string; name: string }>(
|
|
11
|
+
* "SELECT id, name FROM users WHERE id = $1", [userId],
|
|
12
|
+
* );
|
|
13
|
+
* // rows is { id: string; name: string }[]
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* The default is `any` for back-compat — untyped callers continue to work
|
|
17
|
+
* without changes, while new call-sites can opt in to typed rows.
|
|
18
|
+
*/
|
|
19
|
+
query<R = any>(text: string, params?: unknown[]): Promise<{
|
|
20
|
+
rows: R[];
|
|
21
|
+
}>;
|
|
22
|
+
/** Present on `pg.Pool` and `pg.Client`; absent on pglite. */
|
|
23
|
+
connect?(): Promise<PgPoolClient>;
|
|
24
|
+
}
|
|
25
|
+
/** Minimal surface of the dedicated client checked out from a `pg.Pool`. */
|
|
26
|
+
interface PgPoolClient {
|
|
27
|
+
/** @see {@link PgClient.query} */
|
|
28
|
+
query<R = any>(text: string, params?: unknown[]): Promise<{
|
|
29
|
+
rows: R[];
|
|
30
|
+
}>;
|
|
31
|
+
release(): void;
|
|
32
|
+
}
|
|
33
|
+
declare class PostgresStore implements StorePort, GraphPort, DurablePort {
|
|
34
|
+
private readonly client;
|
|
35
|
+
private factIdCounter;
|
|
36
|
+
private readonly newFactId;
|
|
37
|
+
private readonly graphNow;
|
|
38
|
+
/**
|
|
39
|
+
* Construct a PostgresStore wrapping an injected `PgClient`.
|
|
40
|
+
*
|
|
41
|
+
* Pass a `pg.Pool` or a `@electric-sql/pglite` instance as `client`.
|
|
42
|
+
* Note: when using `pg.Pool`, pass a dedicated client or pool — the store
|
|
43
|
+
* issues its own BEGIN/COMMIT on the connection for multi-statement atomicity.
|
|
44
|
+
* For pglite (single-connection WASM), BEGIN/COMMIT on the same client is fine.
|
|
45
|
+
*
|
|
46
|
+
* Call `await store.migrate()` before use, or use `PostgresStore.create()`
|
|
47
|
+
* which runs migrations automatically.
|
|
48
|
+
*/
|
|
49
|
+
constructor(client: PgClient, opts?: {
|
|
50
|
+
newId?: () => string;
|
|
51
|
+
now?: () => string;
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Create a PostgresStore and run migrations in one step.
|
|
55
|
+
* Convenience wrapper for `new PostgresStore(client)` + `migrate()`.
|
|
56
|
+
*/
|
|
57
|
+
static create(opts: {
|
|
58
|
+
client: PgClient;
|
|
59
|
+
newId?: () => string;
|
|
60
|
+
now?: () => string;
|
|
61
|
+
}): Promise<PostgresStore>;
|
|
62
|
+
migrate(): Promise<void>;
|
|
63
|
+
close(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Run `fn` inside a single Postgres transaction.
|
|
66
|
+
*
|
|
67
|
+
* When `this.client` is a `pg.Pool` (has a `connect()` method), we check out
|
|
68
|
+
* a dedicated connection so that BEGIN / body / COMMIT all execute on the same
|
|
69
|
+
* underlying socket — Pool.query() would otherwise dispatch each call to a
|
|
70
|
+
* different pooled connection, destroying atomicity.
|
|
71
|
+
*
|
|
72
|
+
* When `this.client` is pglite (no `connect()`), the client IS the connection;
|
|
73
|
+
* we issue BEGIN/COMMIT directly on it, matching the previous behaviour.
|
|
74
|
+
*/
|
|
75
|
+
private withTransaction;
|
|
76
|
+
createSession(s: SessionRecord): Promise<void>;
|
|
77
|
+
getSession(id: string): Promise<SessionRecord | null>;
|
|
78
|
+
appendEvents(events: StoredEvent[]): Promise<void>;
|
|
79
|
+
readEvents(sessionId: string): Promise<StoredEvent[]>;
|
|
80
|
+
getBlocks(scope: Scope): Promise<MemoryBlock[]>;
|
|
81
|
+
getBlock(scope: Scope, label: string): Promise<MemoryBlock | null>;
|
|
82
|
+
upsertBlock(scope: Scope, block: {
|
|
83
|
+
label: string;
|
|
84
|
+
value: string;
|
|
85
|
+
}, expectVersion?: number): Promise<MemoryBlock>;
|
|
86
|
+
appendBlock(scope: Scope, label: string, text: string): Promise<MemoryBlock>;
|
|
87
|
+
getBlockHistory(scope: Scope, label: string): Promise<BlockHistoryEntry[]>;
|
|
88
|
+
private writeBlock;
|
|
89
|
+
indexMemory(entries: Array<{
|
|
90
|
+
scope: Scope;
|
|
91
|
+
id: string;
|
|
92
|
+
text: string;
|
|
93
|
+
ingestedAt?: number;
|
|
94
|
+
metadata?: Record<string, unknown>;
|
|
95
|
+
}>): Promise<void>;
|
|
96
|
+
searchMemory(scope: Scope, query: string, topK: number): Promise<MemorySnippet[]>;
|
|
97
|
+
private rowToFact;
|
|
98
|
+
assertFact(scope: Scope, input: AssertFactInput): Promise<{
|
|
99
|
+
asserted: Fact;
|
|
100
|
+
invalidated: Fact[];
|
|
101
|
+
}>;
|
|
102
|
+
factHistory(scope: Scope, subject: string, predicate: string): Promise<Fact[]>;
|
|
103
|
+
corroborate(scope: Scope, factId: string, at?: number): Promise<number>;
|
|
104
|
+
expireFacts(scope: Scope, ids: string[], at: string): Promise<number>;
|
|
105
|
+
queryFacts(query: FactQuery): Promise<Fact[]>;
|
|
106
|
+
sweepExpired(scope: Scope, now: string): Promise<number>;
|
|
107
|
+
listSessions(opts?: {
|
|
108
|
+
agentId?: string;
|
|
109
|
+
limit?: number;
|
|
110
|
+
userId?: string;
|
|
111
|
+
orgId?: string;
|
|
112
|
+
}): Promise<SessionRecord[]>;
|
|
113
|
+
listBlocks(scope: Scope): Promise<MemoryBlock[]>;
|
|
114
|
+
eraseScope(scope: Scope): Promise<{
|
|
115
|
+
deleted: number;
|
|
116
|
+
}>;
|
|
117
|
+
writeCheckpoint(sessionId: string, seq: number, hash: string): Promise<void>;
|
|
118
|
+
lastCheckpoint(sessionId: string): Promise<Checkpoint | null>;
|
|
119
|
+
recordIntent(key: string, argsHash: string): Promise<void>;
|
|
120
|
+
recordCompletion(key: string, result: unknown): Promise<void>;
|
|
121
|
+
getIdempotency(key: string): Promise<IdempotencyRecord | null>;
|
|
122
|
+
recordDecision(sessionId: string, callId: string, decision: SuspendDecision): Promise<void>;
|
|
123
|
+
getDecision(sessionId: string, callId: string): Promise<SuspendDecision | null>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { type PgClient, type PgPoolClient, PostgresStore };
|