@elizaos/plugin-sql 2.0.0-alpha.2 → 2.0.0-alpha.20
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/base.d.ts +1102 -0
- package/dist/browser/index.browser.js +3887 -1999
- package/dist/browser/index.browser.js.map +32 -20
- package/dist/browser/index.d.ts +2 -2
- package/dist/cjs/index.d.ts +2 -0
- package/dist/cjs/index.node.cjs +8184 -0
- package/dist/cjs/index.node.cjs.map +67 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -0
- package/dist/index.node.d.ts +17 -0
- package/dist/migration-service.d.ts +17 -0
- package/dist/migrations.d.ts +15 -0
- package/dist/node/index.d.ts +2 -2
- package/dist/node/index.node.js +4411 -8649
- package/dist/node/index.node.js.map +34 -117
- package/dist/pg/adapter.d.ts +41 -0
- package/dist/pg/manager.d.ts +14 -0
- package/dist/pglite/adapter.d.ts +23 -0
- package/dist/pglite/errors.d.ts +20 -0
- package/dist/pglite/manager.d.ts +25 -0
- package/dist/rls.d.ts +13 -0
- package/dist/runtime-migrator/crypto-utils.d.ts +25 -0
- package/dist/runtime-migrator/drizzle-adapters/database-introspector.d.ts +58 -0
- package/dist/runtime-migrator/drizzle-adapters/diff-calculator.d.ts +77 -0
- package/dist/runtime-migrator/drizzle-adapters/snapshot-generator.d.ts +21 -0
- package/dist/runtime-migrator/drizzle-adapters/sql-generator.d.ts +38 -0
- package/dist/runtime-migrator/extension-manager.d.ts +6 -0
- package/dist/runtime-migrator/index.d.ts +8 -0
- package/dist/runtime-migrator/runtime-migrator.d.ts +95 -0
- package/dist/runtime-migrator/schema-transformer.d.ts +18 -0
- package/dist/runtime-migrator/storage/journal-storage.d.ts +10 -0
- package/dist/runtime-migrator/storage/migration-tracker.d.ts +13 -0
- package/dist/runtime-migrator/storage/snapshot-storage.d.ts +9 -0
- package/dist/runtime-migrator/types.d.ts +157 -0
- package/dist/schema/agent.d.ts +344 -0
- package/dist/schema/approvalRequests.d.ts +277 -0
- package/dist/schema/authAuditEvent.d.ts +153 -0
- package/dist/schema/authBootstrapJti.d.ts +49 -0
- package/dist/schema/authIdentity.d.ts +121 -0
- package/dist/schema/authOwnerBinding.d.ts +168 -0
- package/dist/schema/authOwnerLoginToken.d.ts +122 -0
- package/dist/schema/authSession.d.ts +225 -0
- package/dist/schema/cache.d.ts +97 -0
- package/dist/schema/channel.d.ts +177 -0
- package/dist/schema/channelParticipant.d.ts +41 -0
- package/dist/schema/component.d.ts +163 -0
- package/dist/schema/embedding.d.ts +204 -0
- package/dist/schema/entity.d.ts +125 -0
- package/dist/schema/entityIdentity.d.ts +577 -0
- package/dist/schema/index.d.ts +34 -0
- package/dist/schema/log.d.ts +114 -0
- package/dist/schema/longTermMemories.d.ts +254 -0
- package/dist/schema/memory.d.ts +185 -0
- package/dist/schema/memoryAccessLogs.d.ts +109 -0
- package/dist/schema/message.d.ts +194 -0
- package/dist/schema/messageServer.d.ts +126 -0
- package/dist/schema/messageServerAgent.d.ts +41 -0
- package/dist/schema/pairingAllowlist.d.ts +113 -0
- package/dist/schema/pairingRequest.d.ts +147 -0
- package/dist/schema/participant.d.ts +114 -0
- package/dist/schema/relationship.d.ts +156 -0
- package/dist/schema/room.d.ts +195 -0
- package/dist/schema/server.d.ts +64 -0
- package/dist/schema/sessionSummaries.d.ts +273 -0
- package/dist/schema/tasks.d.ts +225 -0
- package/dist/schema/types.d.ts +68 -0
- package/dist/schema/world.d.ts +114 -0
- package/dist/services/advanced-memory-storage.d.ts +36 -0
- package/dist/types.d.ts +13 -0
- package/dist/utils/string-to-uuid.d.ts +2 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.node.d.ts +4 -0
- package/drizzle/index.ts +17 -0
- package/package.json +50 -17
- package/schema/agent.ts +50 -0
- package/schema/approvalRequests.ts +57 -0
- package/schema/authAuditEvent.ts +29 -0
- package/schema/authBootstrapJti.ts +18 -0
- package/schema/authIdentity.ts +35 -0
- package/schema/authOwnerBinding.ts +43 -0
- package/schema/authOwnerLoginToken.ts +50 -0
- package/schema/authSession.ts +44 -0
- package/schema/cache.ts +22 -0
- package/schema/channel.ts +19 -0
- package/schema/channelParticipant.ts +13 -0
- package/schema/component.ts +37 -0
- package/schema/embedding.ts +73 -0
- package/schema/entity.ts +28 -0
- package/schema/entityIdentity.ts +142 -0
- package/schema/index.ts +41 -0
- package/schema/log.ts +38 -0
- package/schema/longTermMemories.ts +27 -0
- package/schema/memory.ts +103 -0
- package/schema/memoryAccessLogs.ts +19 -0
- package/schema/message.ts +24 -0
- package/schema/messageServer.ts +12 -0
- package/schema/messageServerAgent.ts +16 -0
- package/schema/pairingAllowlist.ts +36 -0
- package/schema/pairingRequest.ts +46 -0
- package/schema/participant.ts +43 -0
- package/schema/relationship.ts +50 -0
- package/schema/room.ts +37 -0
- package/schema/server.ts +14 -0
- package/schema/sessionSummaries.ts +27 -0
- package/schema/tasks.ts +24 -0
- package/schema/types.ts +42 -0
- package/schema/world.ts +20 -0
- package/types.ts +19 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type IAgentRuntime, type MemoryStorageProvider, Service, type UUID } from "@elizaos/core";
|
|
2
|
+
type LongTermMemoryRecord = Awaited<ReturnType<MemoryStorageProvider["storeLongTermMemory"]>>;
|
|
3
|
+
type LongTermMemoryInput = Parameters<MemoryStorageProvider["storeLongTermMemory"]>[0];
|
|
4
|
+
type LongTermMemoryCategory = LongTermMemoryRecord["category"];
|
|
5
|
+
type SessionSummaryRecord = Awaited<ReturnType<MemoryStorageProvider["storeSessionSummary"]>>;
|
|
6
|
+
type SessionSummaryInput = Parameters<MemoryStorageProvider["storeSessionSummary"]>[0];
|
|
7
|
+
export declare class AdvancedMemoryStorageService extends Service implements MemoryStorageProvider {
|
|
8
|
+
static serviceType: "memoryStorage";
|
|
9
|
+
capabilityDescription: string;
|
|
10
|
+
static start(runtime: IAgentRuntime): Promise<Service>;
|
|
11
|
+
initialize(runtime: IAgentRuntime): Promise<void>;
|
|
12
|
+
stop(): Promise<void>;
|
|
13
|
+
private getMemoryWorldId;
|
|
14
|
+
private getLongTermRoomId;
|
|
15
|
+
private ensureMemoryWorld;
|
|
16
|
+
private ensureLongTermRoom;
|
|
17
|
+
private getEntityResolutionService;
|
|
18
|
+
private getIdentityGroup;
|
|
19
|
+
private getAnchorEntityId;
|
|
20
|
+
private parseLongTermMemory;
|
|
21
|
+
private parseSessionSummary;
|
|
22
|
+
private sortLongTermMemories;
|
|
23
|
+
private sortSessionSummaries;
|
|
24
|
+
storeLongTermMemory(memory: LongTermMemoryInput): Promise<LongTermMemoryRecord>;
|
|
25
|
+
getLongTermMemories(agentId: UUID, entityId: UUID, opts?: {
|
|
26
|
+
category?: LongTermMemoryCategory;
|
|
27
|
+
limit?: number;
|
|
28
|
+
}): Promise<LongTermMemoryRecord[]>;
|
|
29
|
+
updateLongTermMemory(id: UUID, agentId: UUID, entityId: UUID, updates: Partial<Omit<LongTermMemoryRecord, "id" | "agentId" | "entityId" | "createdAt">>): Promise<void>;
|
|
30
|
+
deleteLongTermMemory(id: UUID, agentId: UUID, entityId: UUID): Promise<void>;
|
|
31
|
+
storeSessionSummary(summary: SessionSummaryInput): Promise<SessionSummaryRecord>;
|
|
32
|
+
getCurrentSessionSummary(agentId: UUID, roomId: UUID): Promise<SessionSummaryRecord | null>;
|
|
33
|
+
updateSessionSummary(id: UUID, agentId: UUID, roomId: UUID, updates: Partial<Omit<SessionSummaryRecord, "id" | "agentId" | "roomId" | "createdAt" | "updatedAt">>): Promise<void>;
|
|
34
|
+
getSessionSummaries(agentId: UUID, roomId: UUID, limit?: number): Promise<SessionSummaryRecord[]>;
|
|
35
|
+
}
|
|
36
|
+
export {};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { IDatabaseAdapter } from "@elizaos/core";
|
|
2
|
+
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
|
3
|
+
import type { PgliteDatabase } from "drizzle-orm/pglite";
|
|
4
|
+
export type DrizzleDatabase = NodePgDatabase | PgliteDatabase;
|
|
5
|
+
export interface IDatabaseClientManager<T> {
|
|
6
|
+
initialize(): Promise<void>;
|
|
7
|
+
getConnection(): T;
|
|
8
|
+
close(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare function getDb(adapter: IDatabaseAdapter): DrizzleDatabase;
|
|
11
|
+
export declare function getRow<T>(result: {
|
|
12
|
+
rows: unknown[];
|
|
13
|
+
}, index?: number): T | undefined;
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function expandTildePath(filepath: string): string;
|
|
2
|
+
export declare function resolveEnvFile(startDir?: string): string;
|
|
3
|
+
export declare function resolvePgliteDir(dir?: string, fallbackDir?: string): string;
|
|
4
|
+
export declare function sanitizeJsonObject(value: unknown, seen?: WeakSet<object>): unknown;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function expandTildePath(filepath: string): string;
|
|
2
|
+
export declare function resolveEnvFile(startDir?: string): string;
|
|
3
|
+
export declare function resolvePgliteDir(dir?: string, fallbackDir?: string): string;
|
|
4
|
+
export declare function sanitizeJsonObject(value: unknown, seen?: WeakSet<object>): unknown;
|
package/drizzle/index.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elizaos/plugin-sql",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/node/index.node.js",
|
|
6
6
|
"module": "dist/node/index.node.js",
|
|
@@ -32,45 +32,67 @@
|
|
|
32
32
|
"default": "./dist/node/index.node.js"
|
|
33
33
|
},
|
|
34
34
|
"default": "./dist/node/index.node.js"
|
|
35
|
+
},
|
|
36
|
+
"./schema": {
|
|
37
|
+
"types": "./schema/index.ts",
|
|
38
|
+
"import": "./schema/index.ts",
|
|
39
|
+
"default": "./schema/index.ts"
|
|
40
|
+
},
|
|
41
|
+
"./drizzle": {
|
|
42
|
+
"types": "./drizzle/index.ts",
|
|
43
|
+
"import": "./drizzle/index.ts",
|
|
44
|
+
"default": "./drizzle/index.ts"
|
|
45
|
+
},
|
|
46
|
+
"./types": {
|
|
47
|
+
"types": "./types.ts",
|
|
48
|
+
"import": "./types.ts",
|
|
49
|
+
"default": "./types.ts"
|
|
35
50
|
}
|
|
36
51
|
},
|
|
37
52
|
"sideEffects": false,
|
|
38
53
|
"files": [
|
|
39
54
|
"dist",
|
|
40
55
|
"drizzle",
|
|
41
|
-
"
|
|
56
|
+
"schema",
|
|
57
|
+
"types.ts"
|
|
42
58
|
],
|
|
43
59
|
"dependencies": {
|
|
44
|
-
"@electric-sql/pglite": "^0.
|
|
45
|
-
"@elizaos/core": "2.0.0-alpha.
|
|
60
|
+
"@electric-sql/pglite": "^0.4.0",
|
|
61
|
+
"@elizaos/core": "^2.0.0-alpha.537",
|
|
62
|
+
"@neondatabase/serverless": "^1.1.0",
|
|
46
63
|
"dotenv": "^17.2.3",
|
|
47
64
|
"drizzle-kit": "^0.31.8",
|
|
48
|
-
"drizzle-orm": "
|
|
65
|
+
"drizzle-orm": "0.45.2",
|
|
49
66
|
"pg": "^8.16.3",
|
|
50
|
-
"uuid": "^
|
|
67
|
+
"uuid": "^14.0.0",
|
|
68
|
+
"ws": "^8.18.3"
|
|
51
69
|
},
|
|
52
70
|
"devDependencies": {
|
|
53
|
-
"@
|
|
71
|
+
"@types/bun": "^1.3.5",
|
|
72
|
+
"@biomejs/biome": "^2.4.14",
|
|
54
73
|
"@types/node": "^25.0.3",
|
|
55
74
|
"@types/pg": "^8.15.6",
|
|
56
|
-
"
|
|
75
|
+
"@types/ws": "^8.18.1",
|
|
76
|
+
"typescript": "^6.0.0",
|
|
77
|
+
"vitest": "^4.0.0"
|
|
57
78
|
},
|
|
58
79
|
"scripts": {
|
|
59
80
|
"dev": "bun run build.ts --watch",
|
|
60
81
|
"migrate:generate": "drizzle-kit generate",
|
|
61
82
|
"migrate": "drizzle-kit migrate",
|
|
62
|
-
"typecheck": "tsc --noEmit -p tsconfig.json
|
|
83
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
63
84
|
"clean": "rm -rf dist .turbo node_modules .turbo-tsconfig.json *.tsbuildinfo",
|
|
64
|
-
"format": "bunx @biomejs/biome format --write .",
|
|
65
|
-
"format:check": "bunx @biomejs/biome format .",
|
|
66
|
-
"lint": "bunx @biomejs/biome check --write --
|
|
67
|
-
"lint:check": "bunx @biomejs/biome check .",
|
|
68
|
-
"test": "
|
|
69
|
-
"test:unit": "
|
|
70
|
-
"test:integration": "
|
|
85
|
+
"format": "bunx @biomejs/biome format --write --config-path ./biome.json .",
|
|
86
|
+
"format:check": "bunx @biomejs/biome format --config-path ./biome.json .",
|
|
87
|
+
"lint": "bunx @biomejs/biome check --write --config-path ./biome.json .",
|
|
88
|
+
"lint:check": "bunx @biomejs/biome check --config-path ./biome.json .",
|
|
89
|
+
"test": "bun run test:real",
|
|
90
|
+
"test:unit": "echo 'unit-only sql tests removed; use bun run test:real'",
|
|
91
|
+
"test:integration": "vitest run __tests__/integration/",
|
|
71
92
|
"test:integration:postgres": "bash scripts/run-integration-tests.sh --postgres",
|
|
72
93
|
"test:migration": "vitest run __tests__/migration/",
|
|
73
94
|
"test:migration:postgres": "vitest run __tests__/migration/",
|
|
95
|
+
"test:real": "bun run test:integration && bun run test:migration",
|
|
74
96
|
"test:e2e:upgrade": "bash __tests__/migration/e2e/run-upgrade-test.sh",
|
|
75
97
|
"test:watch": "vitest",
|
|
76
98
|
"test:coverage": "vitest run --coverage",
|
|
@@ -78,5 +100,16 @@
|
|
|
78
100
|
"build": "bun run build.ts",
|
|
79
101
|
"build:ts": "bun run build.ts"
|
|
80
102
|
},
|
|
81
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "255e37c0e4a76da0b776219db5ebb9dadf20e89f",
|
|
104
|
+
"eliza": {
|
|
105
|
+
"platforms": [
|
|
106
|
+
"browser",
|
|
107
|
+
"node"
|
|
108
|
+
],
|
|
109
|
+
"runtime": "both",
|
|
110
|
+
"platformDetails": {
|
|
111
|
+
"browser": "Browser-compatible build available via exports.browser",
|
|
112
|
+
"node": "Node.js build available via exports.node"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
82
115
|
}
|
package/schema/agent.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { MessageExample } from "@elizaos/core";
|
|
2
|
+
import { sql } from "drizzle-orm";
|
|
3
|
+
import { boolean, jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents a table for storing agent data.
|
|
7
|
+
*
|
|
8
|
+
* @type {Table}
|
|
9
|
+
*/
|
|
10
|
+
export const agentTable = pgTable("agents", {
|
|
11
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
12
|
+
enabled: boolean("enabled").default(true).notNull(),
|
|
13
|
+
server_id: uuid("server_id"),
|
|
14
|
+
createdAt: timestamp("created_at", { withTimezone: true }).default(sql`now()`).notNull(),
|
|
15
|
+
|
|
16
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).default(sql`now()`).notNull(),
|
|
17
|
+
|
|
18
|
+
// Character
|
|
19
|
+
name: text("name").notNull(),
|
|
20
|
+
username: text("username"),
|
|
21
|
+
system: text("system").default(""),
|
|
22
|
+
bio: jsonb("bio").$type<string | string[]>().default(sql`'[]'::jsonb`),
|
|
23
|
+
messageExamples: jsonb("message_examples")
|
|
24
|
+
.$type<MessageExample[][]>()
|
|
25
|
+
.default(sql`'[]'::jsonb`)
|
|
26
|
+
.notNull(),
|
|
27
|
+
postExamples: jsonb("post_examples").$type<string[]>().default(sql`'[]'::jsonb`).notNull(),
|
|
28
|
+
topics: jsonb("topics").$type<string[]>().default(sql`'[]'::jsonb`).notNull(),
|
|
29
|
+
adjectives: jsonb("adjectives").$type<string[]>().default(sql`'[]'::jsonb`).notNull(),
|
|
30
|
+
knowledge: jsonb("knowledge")
|
|
31
|
+
.$type<(string | { path: string; shared?: boolean })[]>()
|
|
32
|
+
.default(sql`'[]'::jsonb`)
|
|
33
|
+
.notNull(),
|
|
34
|
+
plugins: jsonb("plugins").$type<string[]>().default(sql`'[]'::jsonb`).notNull(),
|
|
35
|
+
settings: jsonb("settings")
|
|
36
|
+
.$type<{
|
|
37
|
+
secrets?: { [key: string]: string | boolean | number };
|
|
38
|
+
[key: string]: string | boolean | number | Record<string, unknown> | undefined;
|
|
39
|
+
}>()
|
|
40
|
+
.default(sql`'{}'::jsonb`)
|
|
41
|
+
.notNull(),
|
|
42
|
+
style: jsonb("style")
|
|
43
|
+
.$type<{
|
|
44
|
+
all?: string[];
|
|
45
|
+
chat?: string[];
|
|
46
|
+
post?: string[];
|
|
47
|
+
}>()
|
|
48
|
+
.default(sql`'{}'::jsonb`)
|
|
49
|
+
.notNull(),
|
|
50
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { index, jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|
3
|
+
import { agentTable } from "./agent";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Persistent backing store for the LifeOps human-in-the-loop approval queue.
|
|
7
|
+
*
|
|
8
|
+
* Owned by `apps/app-lifeops` (see `src/lifeops/approval-queue.types.ts`),
|
|
9
|
+
* but lives in plugin-sql so the runtime migrator picks it up automatically
|
|
10
|
+
* for both PostgreSQL and PGlite deployments.
|
|
11
|
+
*
|
|
12
|
+
* Migration safety: this table is additive. It is created on first boot via
|
|
13
|
+
* the runtime migrator when absent, and existing databases are unaffected.
|
|
14
|
+
*
|
|
15
|
+
* State, action, channel, resolved_by, resolution_reason, and resolved_at are
|
|
16
|
+
* intentionally text/timestamp without a CHECK constraint — the application
|
|
17
|
+
* layer is the single source of truth for the state machine and the closed
|
|
18
|
+
* action/channel enums (Commandment 7).
|
|
19
|
+
*/
|
|
20
|
+
export const approvalRequestTable = pgTable(
|
|
21
|
+
"approval_requests",
|
|
22
|
+
{
|
|
23
|
+
id: uuid("id").primaryKey().defaultRandom(),
|
|
24
|
+
/** Lifecycle state. See `ApprovalRequestState` in app-lifeops. */
|
|
25
|
+
state: text("state").notNull(),
|
|
26
|
+
/** Agent or service that enqueued the request. */
|
|
27
|
+
requestedBy: text("requested_by").notNull(),
|
|
28
|
+
/** Owner whose approval is required. */
|
|
29
|
+
subjectUserId: text("subject_user_id").notNull(),
|
|
30
|
+
/** Closed enum from `ApprovalAction`. */
|
|
31
|
+
action: text("action").notNull(),
|
|
32
|
+
/** Discriminated union from `ApprovalPayload`. */
|
|
33
|
+
payload: jsonb("payload").notNull(),
|
|
34
|
+
/** Closed enum from `ApprovalChannel`. */
|
|
35
|
+
channel: text("channel").notNull(),
|
|
36
|
+
/** Required justification for the request. */
|
|
37
|
+
reason: text("reason").notNull(),
|
|
38
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
|
39
|
+
/** Null until the request leaves `pending`. */
|
|
40
|
+
resolvedAt: timestamp("resolved_at", { withTimezone: true }),
|
|
41
|
+
/** Null until resolved; resolver identity. */
|
|
42
|
+
resolvedBy: text("resolved_by"),
|
|
43
|
+
/** Null until resolved; human-readable resolution note. */
|
|
44
|
+
resolutionReason: text("resolution_reason"),
|
|
45
|
+
/** Owning agent (cascade-deletes when the agent is removed). */
|
|
46
|
+
agentId: uuid("agent_id")
|
|
47
|
+
.notNull()
|
|
48
|
+
.references(() => agentTable.id, { onDelete: "cascade" }),
|
|
49
|
+
createdAt: timestamp("created_at", { withTimezone: true }).default(sql`now()`).notNull(),
|
|
50
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).default(sql`now()`).notNull(),
|
|
51
|
+
},
|
|
52
|
+
(table) => [
|
|
53
|
+
index("approval_requests_subject_state_idx").on(table.subjectUserId, table.state),
|
|
54
|
+
index("approval_requests_agent_state_idx").on(table.agentId, table.state),
|
|
55
|
+
index("approval_requests_state_expires_idx").on(table.state, table.expiresAt),
|
|
56
|
+
]
|
|
57
|
+
);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { bigint, index, jsonb, pgTable, text } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Append-only audit row for every sensitive auth action.
|
|
5
|
+
*
|
|
6
|
+
* Rows are also mirrored to JSONL on disk so a wiped DB does not lose history.
|
|
7
|
+
* Token-shaped values in `metadata` MUST be redacted before insert by the
|
|
8
|
+
* caller.
|
|
9
|
+
*/
|
|
10
|
+
export const authAuditEventTable = pgTable(
|
|
11
|
+
"auth_audit_events",
|
|
12
|
+
{
|
|
13
|
+
id: text("id").primaryKey(),
|
|
14
|
+
ts: bigint("ts", { mode: "number" }).notNull(),
|
|
15
|
+
actorIdentityId: text("actor_identity_id"),
|
|
16
|
+
ip: text("ip"),
|
|
17
|
+
userAgent: text("user_agent"),
|
|
18
|
+
action: text("action").notNull(),
|
|
19
|
+
outcome: text("outcome").notNull(),
|
|
20
|
+
metadata: jsonb("metadata").$type<Record<string, string | number | boolean>>().notNull(),
|
|
21
|
+
},
|
|
22
|
+
(table) => [
|
|
23
|
+
index("auth_audit_events_action_idx").on(table.action),
|
|
24
|
+
index("auth_audit_events_ts_idx").on(table.ts),
|
|
25
|
+
index("auth_audit_events_actor_idx").on(table.actorIdentityId),
|
|
26
|
+
]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export type AuthAuditOutcome = "success" | "failure";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { bigint, index, pgTable, text } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Replay-defence set for bootstrap-token `jti` claims. A row exists for every
|
|
5
|
+
* bootstrap token successfully verified on this instance; subsequent
|
|
6
|
+
* presentations of the same `jti` must be rejected.
|
|
7
|
+
*
|
|
8
|
+
* Rows are kept until natural `exp` of the original token plus a buffer; the
|
|
9
|
+
* cleanup job lives in the auth-store.
|
|
10
|
+
*/
|
|
11
|
+
export const authBootstrapJtiSeenTable = pgTable(
|
|
12
|
+
"auth_bootstrap_jti_seen",
|
|
13
|
+
{
|
|
14
|
+
jti: text("jti").primaryKey(),
|
|
15
|
+
seenAt: bigint("seen_at", { mode: "number" }).notNull(),
|
|
16
|
+
},
|
|
17
|
+
(table) => [index("auth_bootstrap_jti_seen_at_idx").on(table.seenAt)]
|
|
18
|
+
);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { bigint, index, pgTable, text } from "drizzle-orm/pg-core";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Auth identity row. One per real user / machine actor on this Eliza instance.
|
|
6
|
+
*
|
|
7
|
+
* `kind` distinguishes interactive ("owner") identities from non-interactive
|
|
8
|
+
* ("machine") identities used by long-lived bearer tokens. Exactly one of
|
|
9
|
+
* `passwordHash` or `cloudUserId` is expected to be populated for an owner
|
|
10
|
+
* (with possible owner-bindings extending login methods); machines have
|
|
11
|
+
* neither and are authenticated by the bearer token bound to their session.
|
|
12
|
+
*/
|
|
13
|
+
export const authIdentityTable = pgTable(
|
|
14
|
+
"auth_identities",
|
|
15
|
+
{
|
|
16
|
+
/** uuid v7 string. Stored as text so we don't have to pull a v7 generator into pg defaults. */
|
|
17
|
+
id: text("id").primaryKey(),
|
|
18
|
+
kind: text("kind").notNull(),
|
|
19
|
+
displayName: text("display_name").notNull(),
|
|
20
|
+
createdAt: bigint("created_at", { mode: "number" }).notNull(),
|
|
21
|
+
/** argon2id encoded password hash. Optional: cloud-only identities may not have one. */
|
|
22
|
+
passwordHash: text("password_hash"),
|
|
23
|
+
/** Linked Eliza Cloud user id when SSO is enabled. */
|
|
24
|
+
cloudUserId: text("cloud_user_id"),
|
|
25
|
+
},
|
|
26
|
+
(table) => [
|
|
27
|
+
index("auth_identities_kind_idx").on(table.kind),
|
|
28
|
+
index("auth_identities_cloud_user_idx").on(table.cloudUserId),
|
|
29
|
+
]
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
export type AuthIdentityKind = "owner" | "machine";
|
|
33
|
+
|
|
34
|
+
/** Default SQL `now() * 1000` to populate `created_at` when callers don't supply one. */
|
|
35
|
+
export const authIdentityCreatedAtDefault = sql`(extract(epoch from now()) * 1000)::bigint`;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { bigint, foreignKey, index, pgTable, text, uniqueIndex } from "drizzle-orm/pg-core";
|
|
2
|
+
import { authIdentityTable } from "./authIdentity";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Connector-owner binding. Lets an external connector account (Discord,
|
|
6
|
+
* Telegram, WeChat, Matrix) prove ownership of a local Eliza identity.
|
|
7
|
+
*
|
|
8
|
+
* Uniqueness is enforced on `(connector, external_id, instance_id)` so the same
|
|
9
|
+
* Discord account can own multiple Eliza instances (one binding per
|
|
10
|
+
* (connector, external) pair *per instance*) without cross-talk.
|
|
11
|
+
*/
|
|
12
|
+
export const authOwnerBindingTable = pgTable(
|
|
13
|
+
"auth_owner_bindings",
|
|
14
|
+
{
|
|
15
|
+
id: text("id").primaryKey(),
|
|
16
|
+
identityId: text("identity_id")
|
|
17
|
+
.notNull()
|
|
18
|
+
.references(() => authIdentityTable.id, { onDelete: "cascade" }),
|
|
19
|
+
connector: text("connector").notNull(),
|
|
20
|
+
externalId: text("external_id").notNull(),
|
|
21
|
+
displayHandle: text("display_handle").notNull(),
|
|
22
|
+
/** Stable per-instance id; populated from ELIZA_INSTANCE_ID or generated once at boot. */
|
|
23
|
+
instanceId: text("instance_id").notNull(),
|
|
24
|
+
verifiedAt: bigint("verified_at", { mode: "number" }).notNull(),
|
|
25
|
+
/** Hashed pairing code (sha256 hex) — never store the plaintext. */
|
|
26
|
+
pendingCodeHash: text("pending_code_hash"),
|
|
27
|
+
pendingExpiresAt: bigint("pending_expires_at", { mode: "number" }),
|
|
28
|
+
},
|
|
29
|
+
(table) => [
|
|
30
|
+
index("auth_owner_bindings_identity_idx").on(table.identityId),
|
|
31
|
+
index("auth_owner_bindings_connector_idx").on(table.connector),
|
|
32
|
+
uniqueIndex("auth_owner_bindings_connector_external_instance_uniq").on(
|
|
33
|
+
table.connector,
|
|
34
|
+
table.externalId,
|
|
35
|
+
table.instanceId
|
|
36
|
+
),
|
|
37
|
+
foreignKey({
|
|
38
|
+
name: "fk_auth_owner_bindings_identity",
|
|
39
|
+
columns: [table.identityId],
|
|
40
|
+
foreignColumns: [authIdentityTable.id],
|
|
41
|
+
}).onDelete("cascade"),
|
|
42
|
+
]
|
|
43
|
+
);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { bigint, foreignKey, index, pgTable, text } from "drizzle-orm/pg-core";
|
|
2
|
+
import { authIdentityTable } from "./authIdentity";
|
|
3
|
+
import { authOwnerBindingTable } from "./authOwnerBinding";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Single-use DM-link login tokens for the connector-owner convenience flow.
|
|
7
|
+
*
|
|
8
|
+
* The user types `/eliza-pair` in their connector and asks Eliza to DM
|
|
9
|
+
* a login link. The DM contains a short-lived URL whose `?token=...` is
|
|
10
|
+
* the SHA-256 hash of a random UUID v7. The plaintext is sent only via the
|
|
11
|
+
* DM channel; the database stores only the hash so a DB read does not
|
|
12
|
+
* surrender unconsumed tokens.
|
|
13
|
+
*
|
|
14
|
+
* Tokens are consumed exactly once: the consume endpoint sets
|
|
15
|
+
* `consumed_at` and the row is preserved for audit. Rows older than
|
|
16
|
+
* `expires_at + 24h` are eligible for cleanup.
|
|
17
|
+
*/
|
|
18
|
+
export const authOwnerLoginTokenTable = pgTable(
|
|
19
|
+
"auth_owner_login_tokens",
|
|
20
|
+
{
|
|
21
|
+
/** SHA-256 hex of the plaintext token. Plaintext is never stored. */
|
|
22
|
+
tokenHash: text("token_hash").primaryKey(),
|
|
23
|
+
identityId: text("identity_id")
|
|
24
|
+
.notNull()
|
|
25
|
+
.references(() => authIdentityTable.id, { onDelete: "cascade" }),
|
|
26
|
+
/** Binding that issued this token. */
|
|
27
|
+
bindingId: text("binding_id")
|
|
28
|
+
.notNull()
|
|
29
|
+
.references(() => authOwnerBindingTable.id, { onDelete: "cascade" }),
|
|
30
|
+
issuedAt: bigint("issued_at", { mode: "number" }).notNull(),
|
|
31
|
+
expiresAt: bigint("expires_at", { mode: "number" }).notNull(),
|
|
32
|
+
/** Set on first successful consume. Null while the token is live. */
|
|
33
|
+
consumedAt: bigint("consumed_at", { mode: "number" }),
|
|
34
|
+
},
|
|
35
|
+
(table) => [
|
|
36
|
+
index("auth_owner_login_tokens_identity_idx").on(table.identityId),
|
|
37
|
+
index("auth_owner_login_tokens_binding_idx").on(table.bindingId),
|
|
38
|
+
index("auth_owner_login_tokens_expires_idx").on(table.expiresAt),
|
|
39
|
+
foreignKey({
|
|
40
|
+
name: "fk_auth_owner_login_tokens_identity",
|
|
41
|
+
columns: [table.identityId],
|
|
42
|
+
foreignColumns: [authIdentityTable.id],
|
|
43
|
+
}).onDelete("cascade"),
|
|
44
|
+
foreignKey({
|
|
45
|
+
name: "fk_auth_owner_login_tokens_binding",
|
|
46
|
+
columns: [table.bindingId],
|
|
47
|
+
foreignColumns: [authOwnerBindingTable.id],
|
|
48
|
+
}).onDelete("cascade"),
|
|
49
|
+
]
|
|
50
|
+
);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { bigint, boolean, foreignKey, index, jsonb, pgTable, text } from "drizzle-orm/pg-core";
|
|
2
|
+
import { authIdentityTable } from "./authIdentity";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Active authenticated session.
|
|
6
|
+
*
|
|
7
|
+
* `id` is the opaque cookie value (256-bit hex) — server-side lookup, never JWT.
|
|
8
|
+
* `kind` is "browser" (sliding TTL, CSRF-bound) or "machine" (absolute TTL,
|
|
9
|
+
* scope-bearing bearer token).
|
|
10
|
+
*
|
|
11
|
+
* Browser sessions store a `csrfSecret` used to derive double-submit tokens.
|
|
12
|
+
* Machine sessions list explicit scopes; browser sessions get an empty list
|
|
13
|
+
* which the auth layer treats as "all scopes".
|
|
14
|
+
*/
|
|
15
|
+
export const authSessionTable = pgTable(
|
|
16
|
+
"auth_sessions",
|
|
17
|
+
{
|
|
18
|
+
id: text("id").primaryKey(),
|
|
19
|
+
identityId: text("identity_id")
|
|
20
|
+
.notNull()
|
|
21
|
+
.references(() => authIdentityTable.id, { onDelete: "cascade" }),
|
|
22
|
+
kind: text("kind").notNull(),
|
|
23
|
+
createdAt: bigint("created_at", { mode: "number" }).notNull(),
|
|
24
|
+
lastSeenAt: bigint("last_seen_at", { mode: "number" }).notNull(),
|
|
25
|
+
expiresAt: bigint("expires_at", { mode: "number" }).notNull(),
|
|
26
|
+
rememberDevice: boolean("remember_device").notNull().default(false),
|
|
27
|
+
csrfSecret: text("csrf_secret").notNull(),
|
|
28
|
+
ip: text("ip"),
|
|
29
|
+
userAgent: text("user_agent"),
|
|
30
|
+
scopes: jsonb("scopes").$type<string[]>().notNull(),
|
|
31
|
+
revokedAt: bigint("revoked_at", { mode: "number" }),
|
|
32
|
+
},
|
|
33
|
+
(table) => [
|
|
34
|
+
index("auth_sessions_identity_idx").on(table.identityId),
|
|
35
|
+
index("auth_sessions_expires_idx").on(table.expiresAt),
|
|
36
|
+
foreignKey({
|
|
37
|
+
name: "fk_auth_sessions_identity",
|
|
38
|
+
columns: [table.identityId],
|
|
39
|
+
foreignColumns: [authIdentityTable.id],
|
|
40
|
+
}).onDelete("cascade"),
|
|
41
|
+
]
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export type AuthSessionKind = "browser" | "machine";
|
package/schema/cache.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { jsonb, pgTable, primaryKey, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|
3
|
+
import { agentTable } from "./agent";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents a PostgreSQL table for caching data.
|
|
7
|
+
*
|
|
8
|
+
* @type {pgTable}
|
|
9
|
+
*/
|
|
10
|
+
export const cacheTable = pgTable(
|
|
11
|
+
"cache",
|
|
12
|
+
{
|
|
13
|
+
key: text("key").notNull(),
|
|
14
|
+
agentId: uuid("agent_id")
|
|
15
|
+
.notNull()
|
|
16
|
+
.references(() => agentTable.id, { onDelete: "cascade" }),
|
|
17
|
+
value: jsonb("value").notNull(),
|
|
18
|
+
createdAt: timestamp("created_at", { withTimezone: true }).default(sql`now()`).notNull(),
|
|
19
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }),
|
|
20
|
+
},
|
|
21
|
+
(table) => [primaryKey({ columns: [table.key, table.agentId] })]
|
|
22
|
+
);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|
3
|
+
import { messageServerTable } from "./messageServer";
|
|
4
|
+
|
|
5
|
+
export const channelTable = pgTable("channels", {
|
|
6
|
+
id: text("id").primaryKey(), // UUID stored as text
|
|
7
|
+
messageServerId: uuid("message_server_id")
|
|
8
|
+
.notNull()
|
|
9
|
+
.references(() => messageServerTable.id, { onDelete: "cascade" }),
|
|
10
|
+
name: text("name").notNull(),
|
|
11
|
+
type: text("type").notNull(), // Store ChannelType enum values as text
|
|
12
|
+
sourceType: text("source_type"),
|
|
13
|
+
sourceId: text("source_id"),
|
|
14
|
+
topic: text("topic"),
|
|
15
|
+
metadata: jsonb("metadata"),
|
|
16
|
+
// server_id is added dynamically by RLS setup
|
|
17
|
+
createdAt: timestamp("created_at", { mode: "date" }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
|
18
|
+
updatedAt: timestamp("updated_at", { mode: "date" }).default(sql`CURRENT_TIMESTAMP`).notNull(),
|
|
19
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { pgTable, primaryKey, text } from "drizzle-orm/pg-core";
|
|
2
|
+
import { channelTable } from "./channel";
|
|
3
|
+
|
|
4
|
+
export const channelParticipantsTable = pgTable(
|
|
5
|
+
"channel_participants",
|
|
6
|
+
{
|
|
7
|
+
channelId: text("channel_id")
|
|
8
|
+
.notNull()
|
|
9
|
+
.references(() => channelTable.id, { onDelete: "cascade" }),
|
|
10
|
+
entityId: text("entity_id").notNull(), // Entity UUID (can be an agentId or a dedicated central user ID)
|
|
11
|
+
},
|
|
12
|
+
(table) => [primaryKey({ columns: [table.channelId, table.entityId] })]
|
|
13
|
+
);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { jsonb, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|
3
|
+
import { agentTable } from "./agent";
|
|
4
|
+
import { entityTable } from "./entity";
|
|
5
|
+
import { roomTable } from "./room";
|
|
6
|
+
import { worldTable } from "./world";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents a component table in the database.
|
|
10
|
+
*/
|
|
11
|
+
export const componentTable = pgTable("components", {
|
|
12
|
+
id: uuid("id").primaryKey().default(sql`gen_random_uuid()`).notNull(),
|
|
13
|
+
|
|
14
|
+
// Foreign keys
|
|
15
|
+
entityId: uuid("entity_id")
|
|
16
|
+
.references(() => entityTable.id, { onDelete: "cascade" })
|
|
17
|
+
.notNull(),
|
|
18
|
+
agentId: uuid("agent_id")
|
|
19
|
+
.references(() => agentTable.id, { onDelete: "cascade" })
|
|
20
|
+
.notNull(),
|
|
21
|
+
roomId: uuid("room_id")
|
|
22
|
+
.references(() => roomTable.id, { onDelete: "cascade" })
|
|
23
|
+
.notNull(),
|
|
24
|
+
worldId: uuid("world_id").references(() => worldTable.id, {
|
|
25
|
+
onDelete: "cascade",
|
|
26
|
+
}),
|
|
27
|
+
sourceEntityId: uuid("source_entity_id").references(() => entityTable.id, {
|
|
28
|
+
onDelete: "cascade",
|
|
29
|
+
}),
|
|
30
|
+
|
|
31
|
+
// Data
|
|
32
|
+
type: text("type").notNull(),
|
|
33
|
+
data: jsonb("data").default(sql`'{}'::jsonb`),
|
|
34
|
+
|
|
35
|
+
// Timestamps
|
|
36
|
+
createdAt: timestamp("created_at").default(sql`now()`).notNull(),
|
|
37
|
+
});
|