feat: add deployable alpha silo

This commit is contained in:
2026-07-11 00:25:45 +08:00
parent 44557da499
commit 9e954790dc
57 changed files with 2792 additions and 400 deletions
+207
View File
@@ -0,0 +1,207 @@
import { createHash } from "node:crypto";
import type { Prisma, PrismaClient } from "@prisma/client";
import { lockActiveOrganization } from "../org/status.js";
export type FeishuPrincipalKind = "USER" | "CHAT" | "DEPARTMENT" | "USER_GROUP" | "EVENT" | "CALLBACK";
export interface ScopedFeishuIdentity {
readonly identityId: string;
readonly connectionId: string;
readonly organizationId: string;
readonly userId: string;
readonly openId: string;
readonly unionId: string | null;
readonly principalId: string;
readonly displayName: string;
readonly avatarUrl: string | null;
}
export function scopedFeishuPrincipalId(
kind: FeishuPrincipalKind,
connectionId: string,
providerLocalId: string,
): string {
const normalizedConnectionId = nonEmpty(connectionId, "Feishu connectionId");
const normalizedProviderLocalId = nonEmpty(providerLocalId, `Feishu ${kind} identifier`);
const digest = createHash("sha256")
.update("cph-feishu-principal\0")
.update(kind, "utf8")
.update("\0")
.update(normalizedConnectionId, "utf8")
.update("\0")
.update(normalizedProviderLocalId, "utf8")
.digest("base64url");
return `feishu:${kind.toLowerCase()}:${normalizedConnectionId}:${digest}`;
}
export async function upsertScopedFeishuIdentity(
prisma: PrismaClient,
input: {
readonly connectionId: string;
readonly openId: string;
readonly unionId?: string | undefined;
readonly displayName: string;
readonly avatarUrl?: string | undefined;
},
): Promise<ScopedFeishuIdentity> {
return prisma.$transaction((tx) => upsertScopedFeishuIdentityInTransaction(tx, input));
}
export async function upsertScopedFeishuIdentityInTransaction(
prisma: Prisma.TransactionClient,
input: {
readonly connectionId: string;
readonly expectedOrganizationId?: string | undefined;
readonly openId: string;
readonly unionId?: string | undefined;
readonly displayName: string;
readonly avatarUrl?: string | undefined;
},
): Promise<ScopedFeishuIdentity> {
const connectionId = nonEmpty(input.connectionId, "Feishu connectionId");
const openId = nonEmpty(input.openId, "Feishu openId");
const displayName = nonEmpty(input.displayName, "Feishu displayName");
const unionId = optionalNonEmpty(input.unionId, "Feishu unionId");
const avatarUrl = optionalNonEmpty(input.avatarUrl, "Feishu avatarUrl");
const principalId = scopedFeishuPrincipalId("USER", connectionId, openId);
const userId = deterministicFeishuUserId(connectionId, openId);
const connection = await lockActiveConnection(prisma, connectionId);
if (input.expectedOrganizationId !== undefined &&
input.expectedOrganizationId !== connection.organizationId) {
throw new Error("Feishu identity Organization scope mismatch");
}
const identity = await prisma.feishuUserIdentity.upsert({
where: { connectionId_openId: { connectionId, openId } },
update: {
...(unionId !== undefined ? { unionId } : {}),
user: {
update: {
displayName,
...(avatarUrl !== undefined ? { avatarUrl } : {}),
},
},
},
create: {
openId,
...(unionId !== undefined ? { unionId } : {}),
connection: { connect: { id: connectionId } },
user: {
connectOrCreate: {
where: { id: userId },
create: {
id: userId,
feishuOpenId: principalId,
displayName,
...(avatarUrl !== undefined ? { avatarUrl } : {}),
},
},
},
},
include: { user: true },
});
return scopedIdentity(connection.organizationId, identity);
}
export async function resolveScopedFeishuIdentity(
prisma: PrismaClient,
input: {
readonly connectionId: string;
readonly openId: string;
readonly expectedOrganizationId?: string | undefined;
},
): Promise<ScopedFeishuIdentity | null> {
const connectionId = nonEmpty(input.connectionId, "Feishu connectionId");
const openId = nonEmpty(input.openId, "Feishu openId");
return prisma.$transaction(async (tx) => {
const connection = await lockActiveConnection(tx, connectionId);
if (input.expectedOrganizationId !== undefined &&
input.expectedOrganizationId !== connection.organizationId) {
throw new Error("Feishu identity Organization scope mismatch");
}
const identity = await tx.feishuUserIdentity.findUnique({
where: { connectionId_openId: { connectionId, openId } },
include: { user: true },
});
return identity === null ? null : scopedIdentity(connection.organizationId, identity);
});
}
async function lockActiveConnection(
prisma: Prisma.TransactionClient,
connectionId: string,
): Promise<{ readonly organizationId: string }> {
const scope = await prisma.organizationFeishuApplicationConnection.findUnique({
where: { id: connectionId },
select: { organizationId: true },
});
if (scope === null) throw new Error("active Feishu Application Connection not found");
await lockActiveOrganization(prisma, scope.organizationId);
await prisma.$queryRaw`
SELECT "id" FROM "OrganizationFeishuApplicationConnection"
WHERE "id" = ${connectionId} FOR SHARE
`;
const connection = await prisma.organizationFeishuApplicationConnection.findUnique({
where: { id: connectionId },
select: {
organizationId: true,
status: true,
activeSecretVersion: { select: { connectionId: true, retiredAt: true } },
},
});
if (connection === null || connection.status !== "ACTIVE" || connection.activeSecretVersion === null ||
connection.organizationId !== scope.organizationId ||
connection.activeSecretVersion.connectionId !== connectionId ||
connection.activeSecretVersion.retiredAt !== null) {
throw new Error("active Feishu Application Connection not found");
}
return { organizationId: connection.organizationId };
}
function scopedIdentity(
organizationId: string,
identity: {
readonly id: string;
readonly connectionId: string;
readonly userId: string;
readonly openId: string;
readonly unionId: string | null;
readonly user: {
readonly displayName: string;
readonly avatarUrl: string | null;
};
},
): ScopedFeishuIdentity {
return {
identityId: identity.id,
connectionId: identity.connectionId,
organizationId,
userId: identity.userId,
openId: identity.openId,
unionId: identity.unionId,
principalId: scopedFeishuPrincipalId("USER", identity.connectionId, identity.openId),
displayName: identity.user.displayName,
avatarUrl: identity.user.avatarUrl,
};
}
export function deterministicFeishuUserId(connectionId: string, openId: string): string {
const digest = createHash("sha256")
.update("cph-feishu-user\0")
.update(connectionId, "utf8")
.update("\0")
.update(openId, "utf8")
.digest("base64url");
return `feishu_${digest}`;
}
function nonEmpty(value: string, label: string): string {
const normalized = value.trim();
if (normalized === "") throw new Error(`${label} is required`);
return normalized;
}
function optionalNonEmpty(value: string | undefined, label: string): string | undefined {
if (value === undefined) return undefined;
return nonEmpty(value, label);
}