@intx/db 0.1.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.
- package/README.md +37 -0
- package/drizzle.config.ts +23 -0
- package/migrations/.gitkeep +0 -0
- package/migrations/0000_brown_wither.sql +50 -0
- package/migrations/0001_white_aqueduct.sql +105 -0
- package/migrations/0002_clever_falcon.sql +56 -0
- package/migrations/0003_stiff_tyrannus.sql +44 -0
- package/migrations/0004_rename_capability_to_offering.sql +1 -0
- package/migrations/0005_gigantic_cardiac.sql +1 -0
- package/migrations/0006_sidecar.sql +8 -0
- package/migrations/0007_agent_running_session.sql +1 -0
- package/migrations/0008_session.sql +10 -0
- package/migrations/0009_session_messages.sql +18 -0
- package/migrations/0010_agent_sidecar_pubkey.sql +2 -0
- package/migrations/0011_session_message_from.sql +2 -0
- package/migrations/0012_agent_instance.sql +22 -0
- package/migrations/0013_instance_session_id.sql +2 -0
- package/migrations/0014_drop_agent_runtime_columns.sql +12 -0
- package/migrations/0015_add_instance_id_to_session_message.sql +2 -0
- package/migrations/0016_jazzy_gamma_corps.sql +3 -0
- package/migrations/0017_hesitant_marvex.sql +1 -0
- package/migrations/0018_natural_sinister_six.sql +5 -0
- package/migrations/0019_rename_grant_source_to_origin.sql +1 -0
- package/migrations/0020_add_agent_role.sql +9 -0
- package/migrations/0021_acoustic_ozymandias.sql +15 -0
- package/migrations/0022_material_sleepwalker.sql +27 -0
- package/migrations/0023_flawless_scarlet_witch.sql +2 -0
- package/migrations/0024_bumpy_sharon_ventura.sql +1 -0
- package/migrations/0025_curvy_firestar.sql +26 -0
- package/migrations/0026_keen_ultimo.sql +13 -0
- package/migrations/0027_git_tokens.sql +21 -0
- package/migrations/0028_wet_sugar_man.sql +1 -0
- package/migrations/meta/0000_snapshot.json +316 -0
- package/migrations/meta/0001_snapshot.json +968 -0
- package/migrations/meta/0002_snapshot.json +1315 -0
- package/migrations/meta/0003_snapshot.json +1594 -0
- package/migrations/meta/0004_snapshot.json +1594 -0
- package/migrations/meta/0005_snapshot.json +1600 -0
- package/migrations/meta/0011_snapshot.json +1921 -0
- package/migrations/meta/0012_snapshot.json +2067 -0
- package/migrations/meta/0013_snapshot.json +2082 -0
- package/migrations/meta/0014_snapshot.json +2049 -0
- package/migrations/meta/0015_snapshot.json +2064 -0
- package/migrations/meta/0016_snapshot.json +2085 -0
- package/migrations/meta/0017_snapshot.json +2085 -0
- package/migrations/meta/0018_snapshot.json +2070 -0
- package/migrations/meta/0019_snapshot.json +2070 -0
- package/migrations/meta/0020_snapshot.json +2126 -0
- package/migrations/meta/0021_snapshot.json +2239 -0
- package/migrations/meta/0022_snapshot.json +2425 -0
- package/migrations/meta/0023_snapshot.json +2260 -0
- package/migrations/meta/0024_snapshot.json +2254 -0
- package/migrations/meta/0025_snapshot.json +2418 -0
- package/migrations/meta/0026_snapshot.json +2508 -0
- package/migrations/meta/0027_snapshot.json +2657 -0
- package/migrations/meta/0028_snapshot.json +2657 -0
- package/migrations/meta/_journal.json +209 -0
- package/package.json +27 -0
- package/src/client.ts +24 -0
- package/src/config.ts +19 -0
- package/src/connection.ts +27 -0
- package/src/credential-resolution.ts +378 -0
- package/src/grant-store.ts +51 -0
- package/src/index.ts +32 -0
- package/src/migrate.test.ts +35 -0
- package/src/migrate.ts +168 -0
- package/src/parse-row.test.ts +113 -0
- package/src/parse-row.ts +185 -0
- package/src/schema/agent-assets.ts +21 -0
- package/src/schema/agents.ts +49 -0
- package/src/schema/assets.ts +24 -0
- package/src/schema/auth.ts +51 -0
- package/src/schema/credentials.ts +43 -0
- package/src/schema/git-tokens.ts +83 -0
- package/src/schema/grants.ts +26 -0
- package/src/schema/index.ts +19 -0
- package/src/schema/instances.ts +36 -0
- package/src/schema/messages.ts +108 -0
- package/src/schema/oauth-clients.ts +26 -0
- package/src/schema/offerings.ts +20 -0
- package/src/schema/principals.ts +28 -0
- package/src/schema/providers.ts +23 -0
- package/src/schema/roles.ts +51 -0
- package/src/schema/session-assets.ts +49 -0
- package/src/schema/sessions.ts +26 -0
- package/src/schema/sidecar.ts +14 -0
- package/src/schema/tenants.ts +41 -0
- package/src/schema/wallets.ts +44 -0
- package/src/tenant-hierarchy.ts +34 -0
- package/tsconfig.json +4 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
export const user = pgTable("user", {
|
|
4
|
+
id: text("id").primaryKey(),
|
|
5
|
+
name: text("name").notNull(),
|
|
6
|
+
email: text("email").notNull().unique(),
|
|
7
|
+
emailVerified: boolean("email_verified").notNull().default(false),
|
|
8
|
+
image: text("image"),
|
|
9
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
10
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export const session = pgTable("session", {
|
|
14
|
+
id: text("id").primaryKey(),
|
|
15
|
+
userId: text("user_id")
|
|
16
|
+
.notNull()
|
|
17
|
+
.references(() => user.id, { onDelete: "cascade" }),
|
|
18
|
+
token: text("token").notNull().unique(),
|
|
19
|
+
expiresAt: timestamp("expires_at").notNull(),
|
|
20
|
+
ipAddress: text("ip_address"),
|
|
21
|
+
userAgent: text("user_agent"),
|
|
22
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
23
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export const account = pgTable("account", {
|
|
27
|
+
id: text("id").primaryKey(),
|
|
28
|
+
userId: text("user_id")
|
|
29
|
+
.notNull()
|
|
30
|
+
.references(() => user.id, { onDelete: "cascade" }),
|
|
31
|
+
accountId: text("account_id").notNull(),
|
|
32
|
+
providerId: text("provider_id").notNull(),
|
|
33
|
+
accessToken: text("access_token"),
|
|
34
|
+
refreshToken: text("refresh_token"),
|
|
35
|
+
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
|
36
|
+
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
|
37
|
+
scope: text("scope"),
|
|
38
|
+
idToken: text("id_token"),
|
|
39
|
+
password: text("password"),
|
|
40
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
41
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export const verification = pgTable("verification", {
|
|
45
|
+
id: text("id").primaryKey(),
|
|
46
|
+
identifier: text("identifier").notNull(),
|
|
47
|
+
value: text("value").notNull(),
|
|
48
|
+
expiresAt: timestamp("expires_at").notNull(),
|
|
49
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
50
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
51
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsonb, pgTable, text, timestamp, unique } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
import { oauthClient } from "./oauth-clients";
|
|
4
|
+
import { principal } from "./principals";
|
|
5
|
+
import { provider } from "./providers";
|
|
6
|
+
import { tenant } from "./tenants";
|
|
7
|
+
|
|
8
|
+
export const credential = pgTable(
|
|
9
|
+
"credential",
|
|
10
|
+
{
|
|
11
|
+
id: text("id").primaryKey(),
|
|
12
|
+
tenantId: text("tenant_id")
|
|
13
|
+
.notNull()
|
|
14
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
15
|
+
principalId: text("principal_id").references(() => principal.id, {
|
|
16
|
+
onDelete: "set null",
|
|
17
|
+
}),
|
|
18
|
+
providerId: text("provider_id")
|
|
19
|
+
.notNull()
|
|
20
|
+
.references(() => provider.id, { onDelete: "cascade" }),
|
|
21
|
+
oauthClientId: text("oauth_client_id").references(() => oauthClient.id, {
|
|
22
|
+
onDelete: "set null",
|
|
23
|
+
}),
|
|
24
|
+
name: text("name").notNull(),
|
|
25
|
+
type: text("type", {
|
|
26
|
+
enum: ["api_key", "oauth_token", "certificate", "other"],
|
|
27
|
+
}).notNull(),
|
|
28
|
+
description: text("description"),
|
|
29
|
+
secret: text("secret").notNull(),
|
|
30
|
+
refreshSecret: text("refresh_secret"),
|
|
31
|
+
scopes: text("scopes").array(),
|
|
32
|
+
expiresAt: timestamp("expires_at"),
|
|
33
|
+
status: text("status", {
|
|
34
|
+
enum: ["active", "expired", "revoked", "error"],
|
|
35
|
+
})
|
|
36
|
+
.notNull()
|
|
37
|
+
.default("active"),
|
|
38
|
+
metadata: jsonb("metadata"),
|
|
39
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
40
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
41
|
+
},
|
|
42
|
+
(t) => [unique("credential_tenant_name").on(t.tenantId, t.name)],
|
|
43
|
+
);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import {
|
|
3
|
+
customType,
|
|
4
|
+
pgTable,
|
|
5
|
+
text,
|
|
6
|
+
timestamp,
|
|
7
|
+
uniqueIndex,
|
|
8
|
+
} from "drizzle-orm/pg-core";
|
|
9
|
+
|
|
10
|
+
import { user } from "./auth";
|
|
11
|
+
import { principal } from "./principals";
|
|
12
|
+
import { tenant } from "./tenants";
|
|
13
|
+
|
|
14
|
+
const bytea = customType<{ data: Uint8Array; driverData: Buffer }>({
|
|
15
|
+
dataType() {
|
|
16
|
+
return "bytea";
|
|
17
|
+
},
|
|
18
|
+
toDriver(value) {
|
|
19
|
+
return Buffer.from(value);
|
|
20
|
+
},
|
|
21
|
+
fromDriver(value) {
|
|
22
|
+
return new Uint8Array(value);
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Hub-issued bearer tokens for the smart-HTTP git endpoints. Opaque
|
|
27
|
+
// tokens of the form `itx_pat_<base64>` or `itx_svc_<base64>` whose
|
|
28
|
+
// SHA-256 digest is stored as `tokenHashSha256` (the raw secret is
|
|
29
|
+
// never persisted). Claims that bound the token's authority are
|
|
30
|
+
// modeled as typed columns rather than JSONB so the lookup path can
|
|
31
|
+
// rely on the database to enforce shape.
|
|
32
|
+
//
|
|
33
|
+
// `userId` identifies the owning user and is always set. `principalId`
|
|
34
|
+
// is set for tenant-bound tokens (the user acting in a specific
|
|
35
|
+
// tenant) and null for personal tokens that are not scoped to a
|
|
36
|
+
// principal. `tenantId` is always set for `kind: "svc"` tokens (they
|
|
37
|
+
// are inherently tenant-bound); for `kind: "pat"` it is set only when
|
|
38
|
+
// the user elected a tenant restriction at mint time. `kind`
|
|
39
|
+
// distinguishes interactive personal access tokens (`pat`) from
|
|
40
|
+
// service tokens (`svc`).
|
|
41
|
+
//
|
|
42
|
+
// `actions` stores the canonical RepoStore action vocabulary
|
|
43
|
+
// (`receivePack`, `createPack`, `resolveRef`, ...). The mint API
|
|
44
|
+
// translates user-facing aliases to canonical names before insert.
|
|
45
|
+
// `resource` is the single substrate authz resource string
|
|
46
|
+
// (e.g. `agent-state:ins_xxx`, `asset:def_yyy`) that the token grants
|
|
47
|
+
// access to. `refPattern` is a glob restricting which refs within the
|
|
48
|
+
// resource the token may read or write.
|
|
49
|
+
//
|
|
50
|
+
// Revocation is soft: setting `revokedAt` prevents future use while
|
|
51
|
+
// preserving the row for audit. The partial unique index on
|
|
52
|
+
// `(user_id, name)` filtered by `revoked_at is null` lets a user
|
|
53
|
+
// reuse a friendly name (e.g. "laptop") after revoking the old
|
|
54
|
+
// token bearing that name.
|
|
55
|
+
export const gitToken = pgTable(
|
|
56
|
+
"git_token",
|
|
57
|
+
{
|
|
58
|
+
id: text("id").primaryKey(),
|
|
59
|
+
tenantId: text("tenant_id").references(() => tenant.id),
|
|
60
|
+
userId: text("user_id")
|
|
61
|
+
.notNull()
|
|
62
|
+
.references(() => user.id, { onDelete: "cascade" }),
|
|
63
|
+
principalId: text("principal_id").references(() => principal.id, {
|
|
64
|
+
onDelete: "cascade",
|
|
65
|
+
}),
|
|
66
|
+
name: text("name").notNull(),
|
|
67
|
+
kind: text("kind", { enum: ["pat", "svc"] }).notNull(),
|
|
68
|
+
tokenHashSha256: bytea("token_hash_sha256").notNull().unique(),
|
|
69
|
+
resource: text("resource").notNull(),
|
|
70
|
+
refPattern: text("ref_pattern").notNull(),
|
|
71
|
+
actions: text("actions").array().notNull(),
|
|
72
|
+
expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
|
|
73
|
+
revokedAt: timestamp("revoked_at", { withTimezone: true }),
|
|
74
|
+
createdAt: timestamp("created_at", { withTimezone: true })
|
|
75
|
+
.notNull()
|
|
76
|
+
.defaultNow(),
|
|
77
|
+
},
|
|
78
|
+
(t) => [
|
|
79
|
+
uniqueIndex("git_token_user_id_name_active_idx")
|
|
80
|
+
.on(t.userId, t.name)
|
|
81
|
+
.where(sql`${t.revokedAt} is null`),
|
|
82
|
+
],
|
|
83
|
+
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
import { principal } from "./principals";
|
|
4
|
+
import { role } from "./roles";
|
|
5
|
+
import { tenant } from "./tenants";
|
|
6
|
+
|
|
7
|
+
export const grant = pgTable("grant", {
|
|
8
|
+
id: text("id").primaryKey(),
|
|
9
|
+
tenantId: text("tenant_id")
|
|
10
|
+
.notNull()
|
|
11
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
12
|
+
roleId: text("role_id").references(() => role.id, { onDelete: "cascade" }),
|
|
13
|
+
principalId: text("principal_id").references(() => principal.id, {
|
|
14
|
+
onDelete: "cascade",
|
|
15
|
+
}),
|
|
16
|
+
resource: text("resource").notNull(),
|
|
17
|
+
action: text("action").notNull(),
|
|
18
|
+
effect: text("effect", { enum: ["allow", "deny", "ask"] }).notNull(),
|
|
19
|
+
conditions: jsonb("conditions"),
|
|
20
|
+
origin: text("origin", {
|
|
21
|
+
enum: ["system", "role", "creator", "invoker"],
|
|
22
|
+
}).notNull(),
|
|
23
|
+
expiresAt: timestamp("expires_at"),
|
|
24
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
25
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
26
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export * from "./auth";
|
|
2
|
+
export * from "./tenants";
|
|
3
|
+
export * from "./principals";
|
|
4
|
+
export * from "./roles";
|
|
5
|
+
export * from "./grants";
|
|
6
|
+
export * from "./agents";
|
|
7
|
+
export * from "./providers";
|
|
8
|
+
export * from "./oauth-clients";
|
|
9
|
+
export * from "./credentials";
|
|
10
|
+
export * from "./assets";
|
|
11
|
+
export * from "./agent-assets";
|
|
12
|
+
export * from "./wallets";
|
|
13
|
+
export * from "./offerings";
|
|
14
|
+
export * from "./sidecar";
|
|
15
|
+
export * from "./sessions";
|
|
16
|
+
export * from "./instances";
|
|
17
|
+
export * from "./session-assets";
|
|
18
|
+
export * from "./messages";
|
|
19
|
+
export * from "./git-tokens";
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
import { agent, agentVersion } from "./agents";
|
|
4
|
+
import { agentSession } from "./sessions";
|
|
5
|
+
import { principal } from "./principals";
|
|
6
|
+
import { sidecar } from "./sidecar";
|
|
7
|
+
import { tenant } from "./tenants";
|
|
8
|
+
|
|
9
|
+
export const agentInstance = pgTable("agent_instance", {
|
|
10
|
+
id: text("id").primaryKey(),
|
|
11
|
+
agentId: text("agent_id")
|
|
12
|
+
.notNull()
|
|
13
|
+
.references(() => agent.id, { onDelete: "cascade" }),
|
|
14
|
+
tenantId: text("tenant_id")
|
|
15
|
+
.notNull()
|
|
16
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
17
|
+
principalId: text("principal_id")
|
|
18
|
+
.notNull()
|
|
19
|
+
.references(() => principal.id),
|
|
20
|
+
address: text("address").notNull().unique(),
|
|
21
|
+
versionId: text("version_id").references(() => agentVersion.id),
|
|
22
|
+
sessionId: text("session_id").references(() => agentSession.id),
|
|
23
|
+
status: text("status", {
|
|
24
|
+
enum: ["deployed", "running", "updating", "error", "stopped"],
|
|
25
|
+
})
|
|
26
|
+
.notNull()
|
|
27
|
+
.default("deployed"),
|
|
28
|
+
sidecarId: text("sidecar_id").references(() => sidecar.id, {
|
|
29
|
+
onDelete: "set null",
|
|
30
|
+
}),
|
|
31
|
+
publicKey: text("public_key"),
|
|
32
|
+
kernelId: text("kernel_id"),
|
|
33
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
34
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
35
|
+
endedAt: timestamp("ended_at"),
|
|
36
|
+
});
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
customType,
|
|
3
|
+
index,
|
|
4
|
+
integer,
|
|
5
|
+
jsonb,
|
|
6
|
+
pgTable,
|
|
7
|
+
text,
|
|
8
|
+
timestamp,
|
|
9
|
+
} from "drizzle-orm/pg-core";
|
|
10
|
+
|
|
11
|
+
import { agentInstance } from "./instances";
|
|
12
|
+
import { agentSession } from "./sessions";
|
|
13
|
+
import { tenant } from "./tenants";
|
|
14
|
+
|
|
15
|
+
const bytea = customType<{ data: Uint8Array; driverData: Buffer }>({
|
|
16
|
+
dataType() {
|
|
17
|
+
return "bytea";
|
|
18
|
+
},
|
|
19
|
+
toDriver(value) {
|
|
20
|
+
return Buffer.from(value);
|
|
21
|
+
},
|
|
22
|
+
fromDriver(value) {
|
|
23
|
+
return new Uint8Array(value);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export const inferenceTurn = pgTable(
|
|
28
|
+
"inference_turn",
|
|
29
|
+
{
|
|
30
|
+
id: text("id").primaryKey(),
|
|
31
|
+
sessionId: text("session_id")
|
|
32
|
+
.notNull()
|
|
33
|
+
.references(() => agentSession.id, { onDelete: "cascade" }),
|
|
34
|
+
instanceId: text("instance_id")
|
|
35
|
+
.notNull()
|
|
36
|
+
.references(() => agentInstance.id, { onDelete: "cascade" }),
|
|
37
|
+
tenantId: text("tenant_id")
|
|
38
|
+
.notNull()
|
|
39
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
40
|
+
model: text("model").notNull(),
|
|
41
|
+
status: text("status", { enum: ["running", "completed", "failed"] })
|
|
42
|
+
.notNull()
|
|
43
|
+
.default("running"),
|
|
44
|
+
startedAt: timestamp("started_at").notNull(),
|
|
45
|
+
endedAt: timestamp("ended_at"),
|
|
46
|
+
},
|
|
47
|
+
(t) => [
|
|
48
|
+
index("inference_turn_instance_id_started_at_idx").on(
|
|
49
|
+
t.instanceId,
|
|
50
|
+
t.startedAt,
|
|
51
|
+
),
|
|
52
|
+
],
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
export const turnPart = pgTable("turn_part", {
|
|
56
|
+
id: text("id").primaryKey(),
|
|
57
|
+
turnId: text("turn_id")
|
|
58
|
+
.notNull()
|
|
59
|
+
.references(() => inferenceTurn.id, { onDelete: "cascade" }),
|
|
60
|
+
sessionId: text("session_id")
|
|
61
|
+
.notNull()
|
|
62
|
+
.references(() => agentSession.id, { onDelete: "cascade" }),
|
|
63
|
+
type: text("type", {
|
|
64
|
+
enum: [
|
|
65
|
+
"text",
|
|
66
|
+
"reasoning",
|
|
67
|
+
"tool",
|
|
68
|
+
"file",
|
|
69
|
+
"error",
|
|
70
|
+
"refusal",
|
|
71
|
+
"step-start",
|
|
72
|
+
"step-finish",
|
|
73
|
+
"snapshot",
|
|
74
|
+
"patch",
|
|
75
|
+
],
|
|
76
|
+
}).notNull(),
|
|
77
|
+
content: text("content"),
|
|
78
|
+
metadata: jsonb("metadata"),
|
|
79
|
+
ordinal: integer("ordinal").notNull(),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export const sessionMail = pgTable(
|
|
83
|
+
"session_mail",
|
|
84
|
+
{
|
|
85
|
+
id: text("id").primaryKey(),
|
|
86
|
+
sessionId: text("session_id")
|
|
87
|
+
.notNull()
|
|
88
|
+
.references(() => agentSession.id, { onDelete: "cascade" }),
|
|
89
|
+
instanceId: text("instance_id").references(() => agentInstance.id, {
|
|
90
|
+
onDelete: "set null",
|
|
91
|
+
}),
|
|
92
|
+
tenantId: text("tenant_id")
|
|
93
|
+
.notNull()
|
|
94
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
95
|
+
direction: text("direction", { enum: ["inbound", "outbound"] }).notNull(),
|
|
96
|
+
status: text("status", { enum: ["pending", "delivered"] })
|
|
97
|
+
.notNull()
|
|
98
|
+
.default("pending"),
|
|
99
|
+
raw: bytea("raw").notNull(),
|
|
100
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
101
|
+
},
|
|
102
|
+
(t) => [
|
|
103
|
+
index("session_mail_instance_id_created_at_idx").on(
|
|
104
|
+
t.instanceId,
|
|
105
|
+
t.createdAt,
|
|
106
|
+
),
|
|
107
|
+
],
|
|
108
|
+
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsonb, pgTable, text, timestamp, unique } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
import { provider } from "./providers";
|
|
4
|
+
import { tenant } from "./tenants";
|
|
5
|
+
|
|
6
|
+
export const oauthClient = pgTable(
|
|
7
|
+
"oauth_client",
|
|
8
|
+
{
|
|
9
|
+
id: text("id").primaryKey(),
|
|
10
|
+
tenantId: text("tenant_id")
|
|
11
|
+
.notNull()
|
|
12
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
13
|
+
providerId: text("provider_id")
|
|
14
|
+
.notNull()
|
|
15
|
+
.references(() => provider.id, { onDelete: "cascade" }),
|
|
16
|
+
name: text("name").notNull(),
|
|
17
|
+
clientId: text("client_id").notNull(),
|
|
18
|
+
clientSecret: text("client_secret").notNull(),
|
|
19
|
+
redirectUris: text("redirect_uris").array(),
|
|
20
|
+
defaultScopes: text("default_scopes").array(),
|
|
21
|
+
metadata: jsonb("metadata"),
|
|
22
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
23
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
24
|
+
},
|
|
25
|
+
(t) => [unique("oauth_client_tenant_provider").on(t.tenantId, t.providerId)],
|
|
26
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
import { agent } from "./agents";
|
|
4
|
+
import { tenant } from "./tenants";
|
|
5
|
+
|
|
6
|
+
export const offering = pgTable("offering", {
|
|
7
|
+
id: text("id").primaryKey(),
|
|
8
|
+
agentId: text("agent_id")
|
|
9
|
+
.notNull()
|
|
10
|
+
.references(() => agent.id, { onDelete: "cascade" }),
|
|
11
|
+
tenantId: text("tenant_id")
|
|
12
|
+
.notNull()
|
|
13
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
14
|
+
name: text("name").notNull(),
|
|
15
|
+
description: text("description"),
|
|
16
|
+
pricing: jsonb("pricing"),
|
|
17
|
+
schema: jsonb("schema"),
|
|
18
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
19
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
20
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { pgTable, text, timestamp, unique } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
import { user } from "./auth";
|
|
4
|
+
import { tenant } from "./tenants";
|
|
5
|
+
|
|
6
|
+
export const principal = pgTable(
|
|
7
|
+
"principal",
|
|
8
|
+
{
|
|
9
|
+
id: text("id").primaryKey(),
|
|
10
|
+
tenantId: text("tenant_id")
|
|
11
|
+
.notNull()
|
|
12
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
13
|
+
kind: text("kind", { enum: ["user", "agent"] }).notNull(),
|
|
14
|
+
refId: text("ref_id").notNull(),
|
|
15
|
+
status: text("status", {
|
|
16
|
+
enum: ["active", "suspended", "invited", "deactivated"],
|
|
17
|
+
}).notNull(),
|
|
18
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
19
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
20
|
+
},
|
|
21
|
+
(t) => [unique().on(t.tenantId, t.kind, t.refId)],
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// The refId on a user principal points to the auth user table.
|
|
25
|
+
// We don't add a FK constraint because refId also points to agent.id
|
|
26
|
+
// when kind='agent', and Postgres can't do conditional FKs.
|
|
27
|
+
// The application layer enforces referential integrity.
|
|
28
|
+
export { user };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsonb, pgTable, text, timestamp, unique } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
import { tenant } from "./tenants";
|
|
4
|
+
|
|
5
|
+
export const provider = pgTable(
|
|
6
|
+
"provider",
|
|
7
|
+
{
|
|
8
|
+
id: text("id").primaryKey(),
|
|
9
|
+
tenantId: text("tenant_id")
|
|
10
|
+
.notNull()
|
|
11
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
12
|
+
name: text("name").notNull(),
|
|
13
|
+
plugin: text("plugin").notNull(),
|
|
14
|
+
authorizationUrl: text("authorization_url"),
|
|
15
|
+
tokenUrl: text("token_url"),
|
|
16
|
+
userInfoUrl: text("user_info_url"),
|
|
17
|
+
scopes: text("scopes").array(),
|
|
18
|
+
metadata: jsonb("metadata"),
|
|
19
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
20
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
21
|
+
},
|
|
22
|
+
(t) => [unique("provider_tenant_name").on(t.tenantId, t.name)],
|
|
23
|
+
);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
boolean,
|
|
3
|
+
pgTable,
|
|
4
|
+
primaryKey,
|
|
5
|
+
text,
|
|
6
|
+
timestamp,
|
|
7
|
+
} from "drizzle-orm/pg-core";
|
|
8
|
+
|
|
9
|
+
import { agent } from "./agents";
|
|
10
|
+
import { principal } from "./principals";
|
|
11
|
+
import { tenant } from "./tenants";
|
|
12
|
+
|
|
13
|
+
export const role = pgTable("role", {
|
|
14
|
+
id: text("id").primaryKey(),
|
|
15
|
+
tenantId: text("tenant_id")
|
|
16
|
+
.notNull()
|
|
17
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
18
|
+
name: text("name").notNull(),
|
|
19
|
+
description: text("description"),
|
|
20
|
+
isSystem: boolean("is_system").notNull().default(false),
|
|
21
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
22
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const agentRole = pgTable(
|
|
26
|
+
"agent_role",
|
|
27
|
+
{
|
|
28
|
+
agentId: text("agent_id")
|
|
29
|
+
.notNull()
|
|
30
|
+
.references(() => agent.id, { onDelete: "cascade" }),
|
|
31
|
+
roleId: text("role_id")
|
|
32
|
+
.notNull()
|
|
33
|
+
.references(() => role.id, { onDelete: "cascade" }),
|
|
34
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
35
|
+
},
|
|
36
|
+
(t) => [primaryKey({ columns: [t.agentId, t.roleId] })],
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export const principalRole = pgTable(
|
|
40
|
+
"principal_role",
|
|
41
|
+
{
|
|
42
|
+
principalId: text("principal_id")
|
|
43
|
+
.notNull()
|
|
44
|
+
.references(() => principal.id, { onDelete: "cascade" }),
|
|
45
|
+
roleId: text("role_id")
|
|
46
|
+
.notNull()
|
|
47
|
+
.references(() => role.id, { onDelete: "cascade" }),
|
|
48
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
49
|
+
},
|
|
50
|
+
(t) => [primaryKey({ columns: [t.principalId, t.roleId] })],
|
|
51
|
+
);
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
index,
|
|
3
|
+
pgTable,
|
|
4
|
+
primaryKey,
|
|
5
|
+
text,
|
|
6
|
+
timestamp,
|
|
7
|
+
} from "drizzle-orm/pg-core";
|
|
8
|
+
|
|
9
|
+
import { agentAsset } from "./agent-assets";
|
|
10
|
+
import { agentInstance } from "./instances";
|
|
11
|
+
|
|
12
|
+
// session_asset rows record per-(instance, agent_asset) pack
|
|
13
|
+
// acknowledgments. A row exists iff the sidecar acked the pack that
|
|
14
|
+
// materialized that asset for that instance. The launchSession flow
|
|
15
|
+
// inserts each row before the corresponding pack send and rolls it
|
|
16
|
+
// back if that single send fails, so each row reflects an ack the
|
|
17
|
+
// hub actually observed for that attachment.
|
|
18
|
+
//
|
|
19
|
+
// Caveat on multi-attachment partial-success: when a session attaches
|
|
20
|
+
// N assets and the fan-out succeeds for attachments 1..k-1 and fails
|
|
21
|
+
// on attachment k, only attachment k's row is rolled back. Rows
|
|
22
|
+
// 1..k-1 stay. The session as a whole never reached the running
|
|
23
|
+
// state — attemptCleanup runs sendAgentUndeploy — but the per-
|
|
24
|
+
// attachment ack invariant holds for the rows that remain.
|
|
25
|
+
// Forensics queries should treat row count as "packs the sidecar
|
|
26
|
+
// acked during this instance's launch," not "sessions that ran with
|
|
27
|
+
// assets." Pairing with agent_instance.status (or its successor
|
|
28
|
+
// session-lifecycle signal) is necessary to distinguish a row left
|
|
29
|
+
// behind by a partially-successful failed launch from one belonging
|
|
30
|
+
// to a fully-running session.
|
|
31
|
+
export const sessionAsset = pgTable(
|
|
32
|
+
"session_asset",
|
|
33
|
+
{
|
|
34
|
+
instanceId: text("instance_id")
|
|
35
|
+
.notNull()
|
|
36
|
+
.references(() => agentInstance.id, { onDelete: "cascade" }),
|
|
37
|
+
agentAssetId: text("agent_asset_id")
|
|
38
|
+
.notNull()
|
|
39
|
+
.references(() => agentAsset.id, { onDelete: "cascade" }),
|
|
40
|
+
mountPath: text("mount_path").notNull(),
|
|
41
|
+
assetPackSha: text("asset_pack_sha").notNull(),
|
|
42
|
+
sourceCommitSha: text("source_commit_sha").notNull(),
|
|
43
|
+
materializedAt: timestamp("materialized_at").notNull().defaultNow(),
|
|
44
|
+
},
|
|
45
|
+
(t) => [
|
|
46
|
+
primaryKey({ columns: [t.instanceId, t.agentAssetId] }),
|
|
47
|
+
index("session_asset_pack_sha_idx").on(t.assetPackSha),
|
|
48
|
+
],
|
|
49
|
+
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
import { agent } from "./agents";
|
|
4
|
+
import { principal } from "./principals";
|
|
5
|
+
import { tenant } from "./tenants";
|
|
6
|
+
|
|
7
|
+
export const agentSession = pgTable("agent_session", {
|
|
8
|
+
id: text("id").primaryKey(),
|
|
9
|
+
tenantId: text("tenant_id")
|
|
10
|
+
.notNull()
|
|
11
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
12
|
+
agentId: text("agent_id")
|
|
13
|
+
.notNull()
|
|
14
|
+
.references(() => agent.id, { onDelete: "cascade" }),
|
|
15
|
+
principalId: text("principal_id")
|
|
16
|
+
.notNull()
|
|
17
|
+
.references(() => principal.id),
|
|
18
|
+
status: text("status", {
|
|
19
|
+
enum: ["active", "ending", "ended"],
|
|
20
|
+
})
|
|
21
|
+
.notNull()
|
|
22
|
+
.default("active"),
|
|
23
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
24
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
25
|
+
endedAt: timestamp("ended_at"),
|
|
26
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
2
|
+
|
|
3
|
+
export const sidecar = pgTable("sidecar", {
|
|
4
|
+
id: text("id").primaryKey(),
|
|
5
|
+
url: text("url").notNull(),
|
|
6
|
+
status: text("status", {
|
|
7
|
+
enum: ["online", "offline", "error"],
|
|
8
|
+
})
|
|
9
|
+
.notNull()
|
|
10
|
+
.default("online"),
|
|
11
|
+
lastHeartbeat: timestamp("last_heartbeat"),
|
|
12
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
13
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
14
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
foreignKey,
|
|
3
|
+
jsonb,
|
|
4
|
+
pgTable,
|
|
5
|
+
text,
|
|
6
|
+
timestamp,
|
|
7
|
+
unique,
|
|
8
|
+
} from "drizzle-orm/pg-core";
|
|
9
|
+
|
|
10
|
+
export const tenant = pgTable(
|
|
11
|
+
"tenant",
|
|
12
|
+
{
|
|
13
|
+
id: text("id").primaryKey(),
|
|
14
|
+
name: text("name").notNull(),
|
|
15
|
+
slug: text("slug").notNull().unique(),
|
|
16
|
+
domain: text("domain").notNull().unique(),
|
|
17
|
+
parentId: text("parent_id"),
|
|
18
|
+
config: jsonb("config"),
|
|
19
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
20
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
21
|
+
},
|
|
22
|
+
(t) => [foreignKey({ columns: [t.parentId], foreignColumns: [t.id] })],
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export const federationTrust = pgTable(
|
|
26
|
+
"federation_trust",
|
|
27
|
+
{
|
|
28
|
+
id: text("id").primaryKey(),
|
|
29
|
+
tenantId: text("tenant_id")
|
|
30
|
+
.notNull()
|
|
31
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
32
|
+
targetTenantId: text("target_tenant_id")
|
|
33
|
+
.notNull()
|
|
34
|
+
.references(() => tenant.id, { onDelete: "cascade" }),
|
|
35
|
+
direction: text("direction", {
|
|
36
|
+
enum: ["inbound", "outbound", "bilateral"],
|
|
37
|
+
}).notNull(),
|
|
38
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
39
|
+
},
|
|
40
|
+
(t) => [unique().on(t.tenantId, t.targetTenantId)],
|
|
41
|
+
);
|