mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
<!-- ELLIPSIS_HIDDEN -->
> [!IMPORTANT]
> Renamed user-related permissions to project-related permissions across
the codebase, affecting enums, schemas, APIs, models, and tests.
>
> - **Behavior**:
> - Renamed `USER` to `PROJECT` in `PermissionScope` enum in
`schema.prisma` and `migration.sql`.
> - Updated `isDefaultUserPermission` to `isDefaultProjectPermission` in
`schema.prisma` and `migration.sql`.
> - Removed `jwks.json/route.ts` file.
> - **API Changes**:
> - Renamed `user-permission-definitions` and `user-permissions`
endpoints to `project-permission-definitions` and `project-permissions`
in `route.tsx` files.
> - Updated CRUD handlers in `crud.tsx` files to reflect new naming.
> - **Models**:
> - Updated models in `permissions.tsx` to use `ProjectPermission` and
`AdminProjectPermission`.
> - Updated `KnownErrors` to use `ProjectPermissionRequired`.
> - **Tests**:
> - Renamed test files and updated test cases in
`e2e/tests/backend/endpoints/api/v1` to reflect new naming.
> - **Misc**:
> - Updated `admin-app-impl.ts`, `client-app-impl.ts`, and
`server-app-impl.ts` to use new project permission naming.
> - Updated `schema-fields.ts` to reflect new permission ID schema.
>
> <sup>This description was created by </sup>[<img alt="Ellipsis"
src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=stack-auth%2Fstack-auth&utm_source=github&utm_medium=referral)<sup>
for 08924f5241. It will automatically
update as commits are pushed.</sup>
<!-- ELLIPSIS_HIDDEN -->
---------
Co-authored-by: Konsti Wohlwend <n2d4xc@gmail.com>
305 lines
8.8 KiB
TypeScript
305 lines
8.8 KiB
TypeScript
import { InternalSession } from "../sessions";
|
|
import { ApiKeysCrud } from "./crud/api-keys";
|
|
import { EmailTemplateCrud, EmailTemplateType } from "./crud/email-templates";
|
|
import { InternalEmailsCrud } from "./crud/emails";
|
|
import { ProjectPermissionDefinitionsCrud } from "./crud/project-permissions";
|
|
import { ProjectsCrud } from "./crud/projects";
|
|
import { SvixTokenCrud } from "./crud/svix-token";
|
|
import { TeamPermissionDefinitionsCrud } from "./crud/team-permissions";
|
|
import { ServerAuthApplicationOptions, StackServerInterface } from "./serverInterface";
|
|
|
|
export type AdminAuthApplicationOptions = ServerAuthApplicationOptions &(
|
|
| {
|
|
superSecretAdminKey: string,
|
|
}
|
|
| {
|
|
projectOwnerSession: InternalSession,
|
|
}
|
|
);
|
|
|
|
export type ApiKeyCreateCrudRequest = {
|
|
has_publishable_client_key: boolean,
|
|
has_secret_server_key: boolean,
|
|
has_super_secret_admin_key: boolean,
|
|
expires_at_millis: number,
|
|
description: string,
|
|
};
|
|
|
|
export type ApiKeyCreateCrudResponse = ApiKeysCrud["Admin"]["Read"] & {
|
|
publishable_client_key?: string,
|
|
secret_server_key?: string,
|
|
super_secret_admin_key?: string,
|
|
};
|
|
|
|
export class StackAdminInterface extends StackServerInterface {
|
|
constructor(public readonly options: AdminAuthApplicationOptions) {
|
|
super(options);
|
|
}
|
|
|
|
public async sendAdminRequest(path: string, options: RequestInit, session: InternalSession | null, requestType: "admin" = "admin") {
|
|
return await this.sendServerRequest(
|
|
path,
|
|
{
|
|
...options,
|
|
headers: {
|
|
"x-stack-super-secret-admin-key": "superSecretAdminKey" in this.options ? this.options.superSecretAdminKey : "",
|
|
...options.headers,
|
|
},
|
|
},
|
|
session,
|
|
requestType,
|
|
);
|
|
}
|
|
|
|
async getProject(): Promise<ProjectsCrud["Admin"]["Read"]> {
|
|
const response = await this.sendAdminRequest(
|
|
"/projects/current",
|
|
{
|
|
method: "GET",
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async updateProject(update: ProjectsCrud["Admin"]["Update"]): Promise<ProjectsCrud["Admin"]["Read"]> {
|
|
const response = await this.sendAdminRequest(
|
|
"/projects/current",
|
|
{
|
|
method: "PATCH",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(update),
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async createApiKey(
|
|
options: ApiKeyCreateCrudRequest,
|
|
): Promise<ApiKeyCreateCrudResponse> {
|
|
const response = await this.sendAdminRequest(
|
|
"/internal/api-keys",
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(options),
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async listApiKeys(): Promise<ApiKeysCrud["Admin"]["Read"][]> {
|
|
const response = await this.sendAdminRequest("/internal/api-keys", {}, null);
|
|
const result = await response.json() as ApiKeysCrud["Admin"]["List"];
|
|
return result.items;
|
|
}
|
|
|
|
async revokeApiKeyById(id: string) {
|
|
await this.sendAdminRequest(
|
|
`/internal/api-keys/${id}`, {
|
|
method: "PATCH",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
revoked: true,
|
|
}),
|
|
},
|
|
null,
|
|
);
|
|
}
|
|
|
|
async getApiKey(id: string, session: InternalSession): Promise<ApiKeysCrud["Admin"]["Read"]> {
|
|
const response = await this.sendAdminRequest(`/internal/api-keys/${id}`, {}, session);
|
|
return await response.json();
|
|
}
|
|
|
|
async listEmailTemplates(): Promise<EmailTemplateCrud['Admin']['Read'][]> {
|
|
const response = await this.sendAdminRequest(`/email-templates`, {}, null);
|
|
const result = await response.json() as EmailTemplateCrud['Admin']['List'];
|
|
return result.items;
|
|
}
|
|
|
|
async updateEmailTemplate(type: EmailTemplateType, data: EmailTemplateCrud['Admin']['Update']): Promise<EmailTemplateCrud['Admin']['Read']> {
|
|
const result = await this.sendAdminRequest(
|
|
`/email-templates/${type}`,
|
|
{
|
|
method: "PATCH",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(data),
|
|
},
|
|
null,
|
|
);
|
|
return await result.json();
|
|
}
|
|
|
|
async resetEmailTemplate(type: EmailTemplateType): Promise<void> {
|
|
await this.sendAdminRequest(
|
|
`/email-templates/${type}`,
|
|
{ method: "DELETE" },
|
|
null
|
|
);
|
|
}
|
|
|
|
// Team permission definitions methods
|
|
async listTeamPermissionDefinitions(): Promise<TeamPermissionDefinitionsCrud['Admin']['Read'][]> {
|
|
const response = await this.sendAdminRequest(`/team-permission-definitions`, {}, null);
|
|
const result = await response.json() as TeamPermissionDefinitionsCrud['Admin']['List'];
|
|
return result.items;
|
|
}
|
|
|
|
async createTeamPermissionDefinition(data: TeamPermissionDefinitionsCrud['Admin']['Create']): Promise<TeamPermissionDefinitionsCrud['Admin']['Read']> {
|
|
const response = await this.sendAdminRequest(
|
|
"/team-permission-definitions",
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(data),
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async updateTeamPermissionDefinition(permissionId: string, data: TeamPermissionDefinitionsCrud['Admin']['Update']): Promise<TeamPermissionDefinitionsCrud['Admin']['Read']> {
|
|
const response = await this.sendAdminRequest(
|
|
`/team-permission-definitions/${permissionId}`,
|
|
{
|
|
method: "PATCH",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(data),
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async deleteTeamPermissionDefinition(permissionId: string): Promise<void> {
|
|
await this.sendAdminRequest(
|
|
`/team-permission-definitions/${permissionId}`,
|
|
{ method: "DELETE" },
|
|
null,
|
|
);
|
|
}
|
|
|
|
async listProjectPermissionDefinitions(): Promise<ProjectPermissionDefinitionsCrud['Admin']['Read'][]> {
|
|
const response = await this.sendAdminRequest(`/project-permission-definitions`, {}, null);
|
|
const result = await response.json() as ProjectPermissionDefinitionsCrud['Admin']['List'];
|
|
return result.items;
|
|
}
|
|
|
|
async createProjectPermissionDefinition(data: ProjectPermissionDefinitionsCrud['Admin']['Create']): Promise<ProjectPermissionDefinitionsCrud['Admin']['Read']> {
|
|
const response = await this.sendAdminRequest(
|
|
"/project-permission-definitions",
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(data),
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async updateProjectPermissionDefinition(permissionId: string, data: ProjectPermissionDefinitionsCrud['Admin']['Update']): Promise<ProjectPermissionDefinitionsCrud['Admin']['Read']> {
|
|
const response = await this.sendAdminRequest(
|
|
`/project-permission-definitions/${permissionId}`,
|
|
{
|
|
method: "PATCH",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(data),
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async deleteProjectPermissionDefinition(permissionId: string): Promise<void> {
|
|
await this.sendAdminRequest(
|
|
`/project-permission-definitions/${permissionId}`,
|
|
{ method: "DELETE" },
|
|
null,
|
|
);
|
|
}
|
|
|
|
async getSvixToken(): Promise<SvixTokenCrud["Admin"]["Read"]> {
|
|
const response = await this.sendAdminRequest(
|
|
"/webhooks/svix-token",
|
|
{
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify({}),
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async deleteProject(): Promise<void> {
|
|
await this.sendAdminRequest(
|
|
"/projects/current",
|
|
{
|
|
method: "DELETE",
|
|
},
|
|
null,
|
|
);
|
|
}
|
|
|
|
async getMetrics(): Promise<any> {
|
|
const response = await this.sendAdminRequest(
|
|
"/internal/metrics",
|
|
{
|
|
method: "GET",
|
|
},
|
|
null,
|
|
);
|
|
return await response.json();
|
|
}
|
|
|
|
async sendTestEmail(data: {
|
|
recipient_email: string,
|
|
email_config: {
|
|
host: string,
|
|
port: number,
|
|
username: string,
|
|
password: string,
|
|
sender_email: string,
|
|
sender_name: string,
|
|
},
|
|
}): Promise<{ success: boolean, error_message?: string }> {
|
|
const response = await this.sendAdminRequest(`/internal/send-test-email`, {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(data),
|
|
}, null);
|
|
return await response.json();
|
|
}
|
|
|
|
async listSentEmails(): Promise<InternalEmailsCrud["Admin"]["List"]> {
|
|
const response = await this.sendAdminRequest("/internal/emails", {
|
|
method: "GET",
|
|
}, null);
|
|
return await response.json();
|
|
}
|
|
}
|