stack/packages/stack-shared/src/interface/serverInterface.ts
2024-06-08 14:55:05 +02:00

363 lines
10 KiB
TypeScript

import {
ClientInterfaceOptions,
UserJson,
StackClientInterface,
OrglikeJson,
UserUpdateJson,
PermissionDefinitionJson,
PermissionDefinitionScopeJson as PermissionDefinitionScopeJson,
TeamMemberJson,
} from "./clientInterface";
import { Result } from "../utils/results";
import { ReadonlyJson } from "../utils/json";
import { EmailTemplateCrud, ListEmailTemplatesCrud } from "./crud/email-templates";
import { InternalSession } from "../sessions";
export type ServerUserJson = UserJson & {
serverMetadata: ReadonlyJson,
};
export type ServerUserUpdateJson = UserUpdateJson & {
serverMetadata?: ReadonlyJson,
primaryEmail?: string | null,
primaryEmailVerified?: boolean,
}
export type ServerOrglikeCustomizableJson = Pick<ServerOrglikeJson, "displayName">;
export type ServerOrglikeJson = OrglikeJson & {};
export type ServerTeamCustomizableJson = ServerOrglikeCustomizableJson;
export type ServerTeamJson = ServerOrglikeJson;
export type ServerTeamMemberJson = TeamMemberJson
export type ServerPermissionDefinitionCustomizableJson = {
readonly id: string,
readonly description?: string,
readonly scope: PermissionDefinitionScopeJson,
readonly containPermissionIds: string[],
};
export type ServerPermissionDefinitionJson = PermissionDefinitionJson & ServerPermissionDefinitionCustomizableJson & {
readonly __databaseUniqueId: string,
readonly scope: PermissionDefinitionScopeJson,
};
export type ServerAuthApplicationOptions = (
& ClientInterfaceOptions
& (
| {
readonly secretServerKey: string,
}
| {
readonly projectOwnerSession: InternalSession,
}
)
);
export const emailTemplateTypes = ['EMAIL_VERIFICATION', 'PASSWORD_RESET', 'MAGIC_LINK'] as const;
export type EmailTemplateType = typeof emailTemplateTypes[number];
export class StackServerInterface extends StackClientInterface {
constructor(public override options: ServerAuthApplicationOptions) {
super(options);
}
protected async sendServerRequest(path: string, options: RequestInit, session: InternalSession | null, requestType: "server" | "admin" = "server") {
return await this.sendClientRequest(
path,
{
...options,
headers: {
"x-stack-secret-server-key": "secretServerKey" in this.options ? this.options.secretServerKey : "",
...options.headers,
},
},
session,
requestType,
);
}
async getServerUserByToken(session: InternalSession): Promise<Result<ServerUserJson>> {
const response = await this.sendServerRequest(
"/current-user?server=true",
{},
session,
);
const user: ServerUserJson | null = await response.json();
if (!user) return Result.error(new Error("Failed to get user"));
return Result.ok(user);
}
async getServerUserById(userId: string): Promise<Result<ServerUserJson>> {
const response = await this.sendServerRequest(
`/users/${userId}?server=true`,
{},
null,
);
const user: ServerUserJson | null = await response.json();
if (!user) return Result.error(new Error("Failed to get user"));
return Result.ok(user);
}
async listServerUserTeamPermissions(
options: {
teamId: string,
type: 'global' | 'team',
direct: boolean,
},
session: InternalSession
): Promise<ServerPermissionDefinitionJson[]> {
const response = await this.sendServerRequest(
`/current-user/teams/${options.teamId}/permissions?type=${options.type}&direct=${options.direct}&server=true`,
{},
session,
);
const permissions: ServerPermissionDefinitionJson[] = await response.json();
return permissions;
}
async listServerUserTeams(session: InternalSession): Promise<ServerTeamJson[]> {
const response = await this.sendServerRequest(
"/current-user/teams?server=true",
{},
session,
);
const teams: ServerTeamJson[] = await response.json();
return teams;
}
async listPermissionDefinitions(): Promise<ServerPermissionDefinitionJson[]> {
const response = await this.sendServerRequest(`/permission-definitions?server=true`, {}, null);
return await response.json();
}
async createPermissionDefinition(data: ServerPermissionDefinitionCustomizableJson): Promise<ServerPermissionDefinitionJson> {
const response = await this.sendServerRequest(
"/permission-definitions?server=true",
{
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({
...data,
scope: {
type: "any-team",
}
}),
},
null,
);
return await response.json();
}
async updatePermissionDefinition(permissionId: string, data: Partial<ServerPermissionDefinitionCustomizableJson>): Promise<void> {
await this.sendServerRequest(
`/permission-definitions/${permissionId}?server=true`,
{
method: "PUT",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(data),
},
null,
);
}
async deletePermissionDefinition(permissionId: string): Promise<void> {
await this.sendServerRequest(
`/permission-definitions/${permissionId}?server=true`,
{ method: "DELETE" },
null,
);
}
async listUsers(): Promise<ServerUserJson[]> {
const response = await this.sendServerRequest("/users?server=true", {}, null);
return await response.json();
}
async listTeams(): Promise<ServerTeamJson[]> {
const response = await this.sendServerRequest("/teams?server=true", {}, null);
const json = await response.json();
return json;
}
async listTeamMembers(teamId: string): Promise<ServerTeamMemberJson[]> {
const response = await this.sendServerRequest(`/teams/${teamId}/users?server=true`, {}, null);
return await response.json();
}
async createTeam(data: ServerTeamCustomizableJson): Promise<ServerTeamJson> {
const response = await this.sendServerRequest(
"/teams?server=true",
{
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(data),
},
null,
);
return await response.json();
}
async updateTeam(teamId: string, data: Partial<ServerTeamCustomizableJson>): Promise<void> {
await this.sendServerRequest(
`/teams/${teamId}?server=true`,
{
method: "PUT",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(data),
},
null,
);
}
async deleteTeam(teamId: string): Promise<void> {
await this.sendServerRequest(
`/teams/${teamId}?server=true`,
{ method: "DELETE" },
null,
);
}
async addUserToTeam(options: {
userId: string,
teamId: string,
}) {
await this.sendServerRequest(
`/teams/${options.teamId}/users/${options.userId}?server=true`,
{
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({}),
},
null,
);
}
async removeUserFromTeam(options: {
userId: string,
teamId: string,
}) {
await this.sendServerRequest(
`/teams/${options.teamId}/users/${options.userId}?server=true`,
{
method: "DELETE",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({}),
},
null,
);
}
async setServerUserCustomizableData(userId: string, update: ServerUserUpdateJson) {
await this.sendServerRequest(
`/users/${userId}?server=true`,
{
method: "PUT",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(update),
},
null,
);
}
async listTeamMemberPermissions(
options: {
teamId: string,
userId: string,
type: 'global' | 'team',
direct: boolean,
}
): Promise<ServerPermissionDefinitionJson[]> {
const response = await this.sendServerRequest(
`/teams/${options.teamId}/users/${options.userId}/permissions?server=true&type=${options.type}&direct=${options.direct}`,
{},
null
);
return await response.json();
}
async grantTeamUserPermission(teamId: string, userId: string, permissionId: string, type: 'global' | 'team') {
await this.sendServerRequest(
`/teams/${teamId}/users/${userId}/permissions/${permissionId}?server=true`,
{
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({ type }),
},
null,
);
}
async revokeTeamUserPermission(teamId: string, userId: string, permissionId: string, type: 'global' | 'team') {
await this.sendServerRequest(
`/teams/${teamId}/users/${userId}/permissions/${permissionId}?server=true`,
{
method: "DELETE",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({ type }),
},
null,
);
}
async deleteServerUser(userId: string) {
await this.sendServerRequest(
`/users/${userId}?server=true`,
{
method: "DELETE",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({}),
},
null,
);
}
async listEmailTemplates(): Promise<ListEmailTemplatesCrud['Server']['Read']> {
const response = await this.sendServerRequest(`/email-templates?server=true`, {}, null);
return await response.json();
}
async updateEmailTemplate(type: EmailTemplateType, data: EmailTemplateCrud['Server']['Update']): Promise<void> {
await this.sendServerRequest(
`/email-templates/${type}?server=true`,
{
method: "PUT",
headers: {
"content-type": "application/json",
},
body: JSON.stringify(data),
},
null,
);
}
async resetEmailTemplate(type: EmailTemplateType): Promise<void> {
await this.sendServerRequest(
`/email-templates/${type}?server=true`,
{ method: "DELETE" },
null,
);
}
}