@intx/db 0.3.0 → 0.4.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/README.md +11 -0
- package/dist/approval-store.d.ts +7 -0
- package/dist/approval-store.js +13 -0
- package/dist/backfill-principal-keys.d.ts +9 -0
- package/dist/backfill-principal-keys.js +51 -0
- package/dist/client.d.ts +27 -2
- package/dist/client.js +6 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -0
- package/dist/connection.js +1 -0
- package/dist/credential-resolution.d.ts +54 -5
- package/dist/credential-resolution.js +109 -0
- package/dist/index.d.ts +11 -5
- package/dist/index.js +10 -4
- package/dist/model-source-resolution.d.ts +6 -5
- package/dist/model-source-resolution.js +42 -13
- package/dist/parse-row.d.ts +39 -8
- package/dist/parse-row.js +8 -0
- package/dist/principal-key-store.d.ts +51 -0
- package/dist/principal-key-store.js +82 -0
- package/dist/principal-store.d.ts +44 -0
- package/dist/principal-store.js +67 -0
- package/dist/schema/approvals.js +5 -0
- package/dist/schema/git-tokens.js +1 -1
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/principal-keys.d.ts +126 -0
- package/dist/schema/principal-keys.js +28 -0
- package/dist/schema/sidecar-allocation.d.ts +19 -40
- package/dist/schema/sidecar-allocation.js +4 -8
- package/dist/schema/sidecar.d.ts +0 -17
- package/dist/schema/sidecar.js +4 -12
- package/dist/schema/tenants.js +13 -3
- package/dist/schema/workflow-probe.d.ts +358 -0
- package/dist/schema/workflow-probe.js +51 -0
- package/dist/schema/workflow-run-dispatch.d.ts +17 -0
- package/dist/schema/workflow-run-dispatch.js +7 -0
- package/dist/schema/workflow-run.d.ts +27 -0
- package/dist/schema/workflow-run.js +8 -0
- package/dist/sender-key-resolver.d.ts +91 -0
- package/dist/sender-key-resolver.js +184 -0
- package/dist/sidecar-allocation-store.d.ts +38 -3
- package/dist/sidecar-allocation-store.js +224 -22
- package/dist/signer-identity.d.ts +12 -0
- package/dist/signer-identity.js +15 -0
- package/dist/tenant-hierarchy.d.ts +2 -0
- package/dist/tenant-hierarchy.js +27 -0
- package/dist/workflow-probe-store.d.ts +47 -0
- package/dist/workflow-probe-store.js +124 -0
- package/dist/workflow-run-dispatch-store.d.ts +3 -0
- package/dist/workflow-run-dispatch-store.js +12 -2
- package/migrations/0085_add_approval_run_idx.sql +1 -0
- package/migrations/0086_cool_human_cannonball.sql +1 -0
- package/migrations/0087_drop_sidecar_placement.sql +3 -0
- package/migrations/0088_thick_sprite.sql +32 -0
- package/migrations/0089_tense_selene.sql +13 -0
- package/migrations/0090_tenant_domain_lower_unique.sql +2 -0
- package/migrations/0091_workflow_run_dispatch_sender_address.sql +21 -0
- package/migrations/0092_sidecar_destroy_failed.sql +4 -0
- package/migrations/0093_sidecar_initialization.sql +2 -0
- package/migrations/meta/0085_snapshot.json +4111 -0
- package/migrations/meta/0086_snapshot.json +4117 -0
- package/migrations/meta/0087_snapshot.json +4100 -0
- package/migrations/meta/0088_snapshot.json +4286 -0
- package/migrations/meta/0089_snapshot.json +4376 -0
- package/migrations/meta/0090_snapshot.json +4387 -0
- package/migrations/meta/0091_snapshot.json +4397 -0
- package/migrations/meta/0092_snapshot.json +4397 -0
- package/migrations/meta/0093_snapshot.json +4407 -0
- package/migrations/meta/_journal.json +63 -0
- package/package.json +6 -5
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export declare const principalKey: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
2
|
+
name: "principal_key";
|
|
3
|
+
schema: undefined;
|
|
4
|
+
columns: {
|
|
5
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
6
|
+
name: "id";
|
|
7
|
+
tableName: "principal_key";
|
|
8
|
+
dataType: "string";
|
|
9
|
+
columnType: "PgText";
|
|
10
|
+
data: string;
|
|
11
|
+
driverParam: string;
|
|
12
|
+
notNull: true;
|
|
13
|
+
hasDefault: false;
|
|
14
|
+
isPrimaryKey: true;
|
|
15
|
+
isAutoincrement: false;
|
|
16
|
+
hasRuntimeDefault: false;
|
|
17
|
+
enumValues: [string, ...string[]];
|
|
18
|
+
baseColumn: never;
|
|
19
|
+
identity: undefined;
|
|
20
|
+
generated: undefined;
|
|
21
|
+
}, {}, {}>;
|
|
22
|
+
principalId: import("drizzle-orm/pg-core").PgColumn<{
|
|
23
|
+
name: "principal_id";
|
|
24
|
+
tableName: "principal_key";
|
|
25
|
+
dataType: "string";
|
|
26
|
+
columnType: "PgText";
|
|
27
|
+
data: string;
|
|
28
|
+
driverParam: string;
|
|
29
|
+
notNull: true;
|
|
30
|
+
hasDefault: false;
|
|
31
|
+
isPrimaryKey: false;
|
|
32
|
+
isAutoincrement: false;
|
|
33
|
+
hasRuntimeDefault: false;
|
|
34
|
+
enumValues: [string, ...string[]];
|
|
35
|
+
baseColumn: never;
|
|
36
|
+
identity: undefined;
|
|
37
|
+
generated: undefined;
|
|
38
|
+
}, {}, {}>;
|
|
39
|
+
publicKey: import("drizzle-orm/pg-core").PgColumn<{
|
|
40
|
+
name: "public_key";
|
|
41
|
+
tableName: "principal_key";
|
|
42
|
+
dataType: "string";
|
|
43
|
+
columnType: "PgText";
|
|
44
|
+
data: string;
|
|
45
|
+
driverParam: string;
|
|
46
|
+
notNull: true;
|
|
47
|
+
hasDefault: false;
|
|
48
|
+
isPrimaryKey: false;
|
|
49
|
+
isAutoincrement: false;
|
|
50
|
+
hasRuntimeDefault: false;
|
|
51
|
+
enumValues: [string, ...string[]];
|
|
52
|
+
baseColumn: never;
|
|
53
|
+
identity: undefined;
|
|
54
|
+
generated: undefined;
|
|
55
|
+
}, {}, {}>;
|
|
56
|
+
privateKey: import("drizzle-orm/pg-core").PgColumn<{
|
|
57
|
+
name: "private_key";
|
|
58
|
+
tableName: "principal_key";
|
|
59
|
+
dataType: "string";
|
|
60
|
+
columnType: "PgText";
|
|
61
|
+
data: string;
|
|
62
|
+
driverParam: string;
|
|
63
|
+
notNull: true;
|
|
64
|
+
hasDefault: false;
|
|
65
|
+
isPrimaryKey: false;
|
|
66
|
+
isAutoincrement: false;
|
|
67
|
+
hasRuntimeDefault: false;
|
|
68
|
+
enumValues: [string, ...string[]];
|
|
69
|
+
baseColumn: never;
|
|
70
|
+
identity: undefined;
|
|
71
|
+
generated: undefined;
|
|
72
|
+
}, {}, {}>;
|
|
73
|
+
status: import("drizzle-orm/pg-core").PgColumn<{
|
|
74
|
+
name: "status";
|
|
75
|
+
tableName: "principal_key";
|
|
76
|
+
dataType: "string";
|
|
77
|
+
columnType: "PgText";
|
|
78
|
+
data: "active" | "retired";
|
|
79
|
+
driverParam: string;
|
|
80
|
+
notNull: true;
|
|
81
|
+
hasDefault: false;
|
|
82
|
+
isPrimaryKey: false;
|
|
83
|
+
isAutoincrement: false;
|
|
84
|
+
hasRuntimeDefault: false;
|
|
85
|
+
enumValues: ["active", "retired"];
|
|
86
|
+
baseColumn: never;
|
|
87
|
+
identity: undefined;
|
|
88
|
+
generated: undefined;
|
|
89
|
+
}, {}, {}>;
|
|
90
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
91
|
+
name: "created_at";
|
|
92
|
+
tableName: "principal_key";
|
|
93
|
+
dataType: "date";
|
|
94
|
+
columnType: "PgTimestamp";
|
|
95
|
+
data: Date;
|
|
96
|
+
driverParam: string;
|
|
97
|
+
notNull: true;
|
|
98
|
+
hasDefault: true;
|
|
99
|
+
isPrimaryKey: false;
|
|
100
|
+
isAutoincrement: false;
|
|
101
|
+
hasRuntimeDefault: false;
|
|
102
|
+
enumValues: undefined;
|
|
103
|
+
baseColumn: never;
|
|
104
|
+
identity: undefined;
|
|
105
|
+
generated: undefined;
|
|
106
|
+
}, {}, {}>;
|
|
107
|
+
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
108
|
+
name: "updated_at";
|
|
109
|
+
tableName: "principal_key";
|
|
110
|
+
dataType: "date";
|
|
111
|
+
columnType: "PgTimestamp";
|
|
112
|
+
data: Date;
|
|
113
|
+
driverParam: string;
|
|
114
|
+
notNull: true;
|
|
115
|
+
hasDefault: true;
|
|
116
|
+
isPrimaryKey: false;
|
|
117
|
+
isAutoincrement: false;
|
|
118
|
+
hasRuntimeDefault: false;
|
|
119
|
+
enumValues: undefined;
|
|
120
|
+
baseColumn: never;
|
|
121
|
+
identity: undefined;
|
|
122
|
+
generated: undefined;
|
|
123
|
+
}, {}, {}>;
|
|
124
|
+
};
|
|
125
|
+
dialect: "pg";
|
|
126
|
+
}>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { pgTable, text, timestamp, uniqueIndex } from "drizzle-orm/pg-core";
|
|
3
|
+
import { principal } from "./principals.js";
|
|
4
|
+
// A principal's Ed25519 signing key. `public_key` is the hex-encoded 32-byte
|
|
5
|
+
// public point; `private_key` holds the hex-encoded 32-byte seed sealed by the
|
|
6
|
+
// credential cipher (`enc:aead:...` ciphertext), so the seed is never at rest in
|
|
7
|
+
// plaintext under a configured key. The hub custodies the private key: a
|
|
8
|
+
// signature attributes an action to the principal, but is not non-repudiable
|
|
9
|
+
// against the hub operator. See docs/AUTH.md.
|
|
10
|
+
//
|
|
11
|
+
// The `status` axis expresses the one-active-key-per-principal invariant, which
|
|
12
|
+
// the partial unique index below enforces at the database. No path retires a
|
|
13
|
+
// key; every key a principal holds today is "active".
|
|
14
|
+
export const principalKey = pgTable("principal_key", {
|
|
15
|
+
id: text("id").primaryKey(),
|
|
16
|
+
principalId: text("principal_id")
|
|
17
|
+
.notNull()
|
|
18
|
+
.references(() => principal.id, { onDelete: "cascade" }),
|
|
19
|
+
publicKey: text("public_key").notNull().unique(),
|
|
20
|
+
privateKey: text("private_key").notNull(),
|
|
21
|
+
status: text("status", { enum: ["active", "retired"] }).notNull(),
|
|
22
|
+
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
23
|
+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
24
|
+
}, (t) => [
|
|
25
|
+
uniqueIndex("principal_key_one_active")
|
|
26
|
+
.on(t.principalId)
|
|
27
|
+
.where(sql `${t.status} = 'active'`),
|
|
28
|
+
]);
|
|
@@ -123,50 +123,12 @@ export declare const sidecarAllocation: import("drizzle-orm/pg-core").PgTableWit
|
|
|
123
123
|
identity: undefined;
|
|
124
124
|
generated: undefined;
|
|
125
125
|
}, {}, {}>;
|
|
126
|
-
placementSharing: import("drizzle-orm/pg-core").PgColumn<{
|
|
127
|
-
name: "placement_sharing";
|
|
128
|
-
tableName: "sidecar_allocation";
|
|
129
|
-
dataType: "string";
|
|
130
|
-
columnType: "PgText";
|
|
131
|
-
data: "exclusive";
|
|
132
|
-
driverParam: string;
|
|
133
|
-
notNull: true;
|
|
134
|
-
hasDefault: false;
|
|
135
|
-
isPrimaryKey: false;
|
|
136
|
-
isAutoincrement: false;
|
|
137
|
-
hasRuntimeDefault: false;
|
|
138
|
-
enumValues: [string, ...string[]];
|
|
139
|
-
baseColumn: never;
|
|
140
|
-
identity: undefined;
|
|
141
|
-
generated: undefined;
|
|
142
|
-
}, {}, {
|
|
143
|
-
$type: "exclusive";
|
|
144
|
-
}>;
|
|
145
|
-
sidecarReuse: import("drizzle-orm/pg-core").PgColumn<{
|
|
146
|
-
name: "sidecar_reuse";
|
|
147
|
-
tableName: "sidecar_allocation";
|
|
148
|
-
dataType: "string";
|
|
149
|
-
columnType: "PgText";
|
|
150
|
-
data: "never" | "same-deployment";
|
|
151
|
-
driverParam: string;
|
|
152
|
-
notNull: true;
|
|
153
|
-
hasDefault: true;
|
|
154
|
-
isPrimaryKey: false;
|
|
155
|
-
isAutoincrement: false;
|
|
156
|
-
hasRuntimeDefault: false;
|
|
157
|
-
enumValues: [string, ...string[]];
|
|
158
|
-
baseColumn: never;
|
|
159
|
-
identity: undefined;
|
|
160
|
-
generated: undefined;
|
|
161
|
-
}, {}, {
|
|
162
|
-
$type: "never" | "same-deployment";
|
|
163
|
-
}>;
|
|
164
126
|
status: import("drizzle-orm/pg-core").PgColumn<{
|
|
165
127
|
name: "status";
|
|
166
128
|
tableName: "sidecar_allocation";
|
|
167
129
|
dataType: "string";
|
|
168
130
|
columnType: "PgText";
|
|
169
|
-
data: "failed" | "
|
|
131
|
+
data: "failed" | "pending" | "releasing" | "released" | "destroy_failed" | "provisioning" | "allocated" | "replacing";
|
|
170
132
|
driverParam: string;
|
|
171
133
|
notNull: true;
|
|
172
134
|
hasDefault: true;
|
|
@@ -178,7 +140,7 @@ export declare const sidecarAllocation: import("drizzle-orm/pg-core").PgTableWit
|
|
|
178
140
|
identity: undefined;
|
|
179
141
|
generated: undefined;
|
|
180
142
|
}, {}, {
|
|
181
|
-
$type: "failed" | "
|
|
143
|
+
$type: "failed" | "pending" | "releasing" | "released" | "destroy_failed" | "provisioning" | "allocated" | "replacing";
|
|
182
144
|
}>;
|
|
183
145
|
generation: import("drizzle-orm/pg-core").PgColumn<{
|
|
184
146
|
name: "generation";
|
|
@@ -282,6 +244,23 @@ export declare const sidecarAllocation: import("drizzle-orm/pg-core").PgTableWit
|
|
|
282
244
|
identity: undefined;
|
|
283
245
|
generated: undefined;
|
|
284
246
|
}, {}, {}>;
|
|
247
|
+
initializationLeaseId: import("drizzle-orm/pg-core").PgColumn<{
|
|
248
|
+
name: "initialization_lease_id";
|
|
249
|
+
tableName: "sidecar_allocation";
|
|
250
|
+
dataType: "string";
|
|
251
|
+
columnType: "PgText";
|
|
252
|
+
data: string;
|
|
253
|
+
driverParam: string;
|
|
254
|
+
notNull: false;
|
|
255
|
+
hasDefault: false;
|
|
256
|
+
isPrimaryKey: false;
|
|
257
|
+
isAutoincrement: false;
|
|
258
|
+
hasRuntimeDefault: false;
|
|
259
|
+
enumValues: [string, ...string[]];
|
|
260
|
+
baseColumn: never;
|
|
261
|
+
identity: undefined;
|
|
262
|
+
generated: undefined;
|
|
263
|
+
}, {}, {}>;
|
|
285
264
|
ensureAttempts: import("drizzle-orm/pg-core").PgColumn<{
|
|
286
265
|
name: "ensure_attempts";
|
|
287
266
|
tableName: "sidecar_allocation";
|
|
@@ -19,11 +19,6 @@ export const sidecarAllocation = pgTable("sidecar_allocation", {
|
|
|
19
19
|
sidecarId: text("sidecar_id").references(() => sidecar.id, {
|
|
20
20
|
onDelete: "restrict",
|
|
21
21
|
}),
|
|
22
|
-
placementSharing: text("placement_sharing").$type().notNull(),
|
|
23
|
-
sidecarReuse: text("sidecar_reuse")
|
|
24
|
-
.$type()
|
|
25
|
-
.notNull()
|
|
26
|
-
.default("never"),
|
|
27
22
|
status: text("status")
|
|
28
23
|
.$type()
|
|
29
24
|
.notNull()
|
|
@@ -34,6 +29,7 @@ export const sidecarAllocation = pgTable("sidecar_allocation", {
|
|
|
34
29
|
nextAttemptAt: timestamp("next_attempt_at"),
|
|
35
30
|
reconciliationLeaseId: text("reconciliation_lease_id"),
|
|
36
31
|
reconciliationLeaseExpiresAt: timestamp("reconciliation_lease_expires_at"),
|
|
32
|
+
initializationLeaseId: text("initialization_lease_id"),
|
|
37
33
|
ensureAttempts: integer("ensure_attempts").notNull().default(0),
|
|
38
34
|
destroyAttempts: integer("destroy_attempts").notNull().default(0),
|
|
39
35
|
connectDeadline: timestamp("connect_deadline"),
|
|
@@ -45,13 +41,13 @@ export const sidecarAllocation = pgTable("sidecar_allocation", {
|
|
|
45
41
|
uniqueIndex("sidecar_allocation_anchor_run_idx").on(t.anchorRunId),
|
|
46
42
|
uniqueIndex("sidecar_allocation_active_sidecar_idx")
|
|
47
43
|
.on(t.sidecarId)
|
|
48
|
-
.where(sql `${t.status} in ('provisioning', 'allocated', 'replacing', 'releasing')`),
|
|
44
|
+
.where(sql `${t.status} in ('provisioning', 'allocated', 'replacing', 'releasing', 'destroy_failed')`),
|
|
49
45
|
index("sidecar_allocation_sidecar_idx").on(t.sidecarId),
|
|
50
46
|
index("sidecar_allocation_reconciliation_idx")
|
|
51
47
|
.on(t.nextAttemptAt, t.createdAt)
|
|
52
48
|
.where(sql `${t.status} in ('pending', 'provisioning', 'allocated', 'replacing', 'releasing') and ${t.nextAttemptAt} is not null`),
|
|
53
|
-
check("sidecar_allocation_status_check", sql `${t.status} in ('pending', 'provisioning', 'allocated', 'replacing', 'releasing', 'released', 'failed')`),
|
|
54
|
-
check("sidecar_allocation_placement_check", sql `${t.placementSharing} = 'exclusive'`),
|
|
49
|
+
check("sidecar_allocation_status_check", sql `${t.status} in ('pending', 'provisioning', 'allocated', 'replacing', 'releasing', 'destroy_failed', 'released', 'failed')`),
|
|
55
50
|
check("sidecar_allocation_generation_check", sql `${t.generation} >= 0`),
|
|
56
51
|
check("sidecar_allocation_accepted_generation_check", sql `${t.ensureAcceptedGeneration} is null or ${t.ensureAcceptedGeneration} <= ${t.generation}`),
|
|
52
|
+
check("sidecar_allocation_initialization_check", sql `${t.initializationLeaseId} is null or (${t.status} = 'allocated' and ${t.ensureAcceptedGeneration} is not null and ${t.ensureAcceptedGeneration} = ${t.generation})`),
|
|
57
53
|
]);
|
package/dist/schema/sidecar.d.ts
CHANGED
|
@@ -55,23 +55,6 @@ export declare const sidecar: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
55
55
|
}, {}, {
|
|
56
56
|
pgColumnBuilderBrand: "PgCustomColumnBuilderBrand";
|
|
57
57
|
}>;
|
|
58
|
-
credentialScope: import("drizzle-orm/pg-core").PgColumn<{
|
|
59
|
-
name: "credential_scope";
|
|
60
|
-
tableName: "sidecar";
|
|
61
|
-
dataType: "string";
|
|
62
|
-
columnType: "PgText";
|
|
63
|
-
data: "shared" | "allocated";
|
|
64
|
-
driverParam: string;
|
|
65
|
-
notNull: true;
|
|
66
|
-
hasDefault: true;
|
|
67
|
-
isPrimaryKey: false;
|
|
68
|
-
isAutoincrement: false;
|
|
69
|
-
hasRuntimeDefault: false;
|
|
70
|
-
enumValues: ["shared", "allocated"];
|
|
71
|
-
baseColumn: never;
|
|
72
|
-
identity: undefined;
|
|
73
|
-
generated: undefined;
|
|
74
|
-
}, {}, {}>;
|
|
75
58
|
status: import("drizzle-orm/pg-core").PgColumn<{
|
|
76
59
|
name: "status";
|
|
77
60
|
tableName: "sidecar";
|
package/dist/schema/sidecar.js
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { check, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
1
|
+
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
3
2
|
import { bytea } from "./column-types.js";
|
|
4
3
|
export const sidecar = pgTable("sidecar", {
|
|
5
4
|
id: text("id").primaryKey(),
|
|
6
|
-
//
|
|
7
|
-
// do not have an endpoint until registration completes.
|
|
5
|
+
// Provisioned probe/allocation identities exist before their infrastructure
|
|
6
|
+
// connects, so they do not have an endpoint until registration completes.
|
|
8
7
|
url: text("url"),
|
|
9
8
|
// SHA-256 digest of the sidecar's bearer token, presented on the
|
|
10
9
|
// WebSocket handshake and matched against this column. Only the digest
|
|
11
10
|
// is stored; the raw token is never persisted.
|
|
12
11
|
tokenHashSha256: bytea("token_hash_sha256").notNull().unique(),
|
|
13
|
-
credentialScope: text("credential_scope", {
|
|
14
|
-
enum: ["shared", "allocated"],
|
|
15
|
-
})
|
|
16
|
-
.notNull()
|
|
17
|
-
.default("shared"),
|
|
18
12
|
status: text("status", {
|
|
19
13
|
enum: ["online", "offline", "error"],
|
|
20
14
|
})
|
|
@@ -23,6 +17,4 @@ export const sidecar = pgTable("sidecar", {
|
|
|
23
17
|
lastHeartbeat: timestamp("last_heartbeat"),
|
|
24
18
|
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
25
19
|
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
26
|
-
}
|
|
27
|
-
check("sidecar_credential_scope_check", sql `${t.credentialScope} in ('shared', 'allocated')`),
|
|
28
|
-
]);
|
|
20
|
+
});
|
package/dist/schema/tenants.js
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import { foreignKey, jsonb, pgTable, text, timestamp, unique, uniqueIndex, } from "drizzle-orm/pg-core";
|
|
2
3
|
export const tenant = pgTable("tenant", {
|
|
3
4
|
id: text("id").primaryKey(),
|
|
4
5
|
name: text("name").notNull(),
|
|
5
6
|
slug: text("slug").notNull().unique(),
|
|
6
|
-
|
|
7
|
+
// Unique on `lower(domain)`, not the raw column: an inbound mail `From` is
|
|
8
|
+
// lowercased when parsed, so a sender address must map to exactly one
|
|
9
|
+
// tenant. A case-sensitive unique would let case-variant domains coexist and
|
|
10
|
+
// let a case-variant registration shadow another tenant's senders. The
|
|
11
|
+
// creation boundary lowercases the domain; this index enforces it for every
|
|
12
|
+
// write path.
|
|
13
|
+
domain: text("domain").notNull(),
|
|
7
14
|
parentId: text("parent_id"),
|
|
8
15
|
config: jsonb("config"),
|
|
9
16
|
createdAt: timestamp("created_at").notNull().defaultNow(),
|
|
10
17
|
updatedAt: timestamp("updated_at").notNull().defaultNow(),
|
|
11
|
-
}, (t) => [
|
|
18
|
+
}, (t) => [
|
|
19
|
+
foreignKey({ columns: [t.parentId], foreignColumns: [t.id] }),
|
|
20
|
+
uniqueIndex("tenant_domain_lower_idx").on(sql `lower(${t.domain})`),
|
|
21
|
+
]);
|
|
12
22
|
export const federationTrust = pgTable("federation_trust", {
|
|
13
23
|
id: text("id").primaryKey(),
|
|
14
24
|
tenantId: text("tenant_id")
|