diff --git a/apps/backend/src/app/api/latest/project-permission-definitions/[permission_id]/route.tsx b/apps/backend/src/app/api/latest/project-permission-definitions/[permission_id]/route.tsx index a25252a69..52902a823 100644 --- a/apps/backend/src/app/api/latest/project-permission-definitions/[permission_id]/route.tsx +++ b/apps/backend/src/app/api/latest/project-permission-definitions/[permission_id]/route.tsx @@ -1,4 +1,4 @@ -import { userPermissionDefinitionsCrudHandlers } from "../crud"; +import { projectPermissionDefinitionsCrudHandlers } from "../crud"; -export const PATCH = userPermissionDefinitionsCrudHandlers.updateHandler; -export const DELETE = userPermissionDefinitionsCrudHandlers.deleteHandler; +export const PATCH = projectPermissionDefinitionsCrudHandlers.updateHandler; +export const DELETE = projectPermissionDefinitionsCrudHandlers.deleteHandler; diff --git a/apps/backend/src/app/api/latest/project-permission-definitions/crud.tsx b/apps/backend/src/app/api/latest/project-permission-definitions/crud.tsx index 1fb625be2..46f020236 100644 --- a/apps/backend/src/app/api/latest/project-permission-definitions/crud.tsx +++ b/apps/backend/src/app/api/latest/project-permission-definitions/crud.tsx @@ -1,11 +1,11 @@ import { createPermissionDefinition, deletePermissionDefinition, listPermissionDefinitions, updatePermissionDefinitions } from "@/lib/permissions"; import { retryTransaction } from "@/prisma-client"; import { createCrudHandlers } from "@/route-handlers/crud-handler"; -import { userPermissionDefinitionsCrud } from '@stackframe/stack-shared/dist/interface/crud/user-permissions'; +import { projectPermissionDefinitionsCrud } from '@stackframe/stack-shared/dist/interface/crud/project-permissions'; import { teamPermissionDefinitionIdSchema, yupObject } from "@stackframe/stack-shared/dist/schema-fields"; import { createLazyProxy } from "@stackframe/stack-shared/dist/utils/proxies"; -export const userPermissionDefinitionsCrudHandlers = createLazyProxy(() => createCrudHandlers(userPermissionDefinitionsCrud, { +export const projectPermissionDefinitionsCrudHandlers = createLazyProxy(() => createCrudHandlers(projectPermissionDefinitionsCrud, { paramsSchema: yupObject({ permission_id: teamPermissionDefinitionIdSchema.defined(), }), diff --git a/apps/backend/src/app/api/latest/project-permission-definitions/route.tsx b/apps/backend/src/app/api/latest/project-permission-definitions/route.tsx index 3a5d328cc..e4c2c2996 100644 --- a/apps/backend/src/app/api/latest/project-permission-definitions/route.tsx +++ b/apps/backend/src/app/api/latest/project-permission-definitions/route.tsx @@ -1,4 +1,4 @@ -import { userPermissionDefinitionsCrudHandlers } from "./crud"; +import { projectPermissionDefinitionsCrudHandlers } from "./crud"; -export const POST = userPermissionDefinitionsCrudHandlers.createHandler; -export const GET = userPermissionDefinitionsCrudHandlers.listHandler; +export const POST = projectPermissionDefinitionsCrudHandlers.createHandler; +export const GET = projectPermissionDefinitionsCrudHandlers.listHandler; diff --git a/apps/backend/src/app/api/latest/project-permissions/[user_id]/[permission_id]/route.tsx b/apps/backend/src/app/api/latest/project-permissions/[user_id]/[permission_id]/route.tsx index 7e57ae857..be85633df 100644 --- a/apps/backend/src/app/api/latest/project-permissions/[user_id]/[permission_id]/route.tsx +++ b/apps/backend/src/app/api/latest/project-permissions/[user_id]/[permission_id]/route.tsx @@ -1,4 +1,4 @@ -import { userPermissionsCrudHandlers } from "../../crud"; +import { projectPermissionsCrudHandlers } from "../../crud"; -export const POST = userPermissionsCrudHandlers.createHandler; -export const DELETE = userPermissionsCrudHandlers.deleteHandler; +export const POST = projectPermissionsCrudHandlers.createHandler; +export const DELETE = projectPermissionsCrudHandlers.deleteHandler; diff --git a/apps/backend/src/app/api/latest/project-permissions/crud.tsx b/apps/backend/src/app/api/latest/project-permissions/crud.tsx index c7219acc7..e9587789c 100644 --- a/apps/backend/src/app/api/latest/project-permissions/crud.tsx +++ b/apps/backend/src/app/api/latest/project-permissions/crud.tsx @@ -1,16 +1,16 @@ import { grantUserPermission, listUserPermissions, revokeUserPermission } from "@/lib/permissions"; import { ensureUserExists, ensureUserPermissionExists } from "@/lib/request-checks"; -import { sendUserPermissionCreatedWebhook, sendUserPermissionDeletedWebhook } from "@/lib/webhooks"; +import { sendProjectPermissionCreatedWebhook, sendProjectPermissionDeletedWebhook } from "@/lib/webhooks"; import { retryTransaction } from "@/prisma-client"; import { createCrudHandlers } from "@/route-handlers/crud-handler"; import { runAsynchronouslyAndWaitUntil } from "@/utils/vercel"; import { KnownErrors } from "@stackframe/stack-shared"; -import { userPermissionsCrud } from '@stackframe/stack-shared/dist/interface/crud/user-permissions'; +import { projectPermissionsCrud } from '@stackframe/stack-shared/dist/interface/crud/project-permissions'; import { teamPermissionDefinitionIdSchema, userIdOrMeSchema, yupObject, yupString } from "@stackframe/stack-shared/dist/schema-fields"; import { StatusError, throwErr } from "@stackframe/stack-shared/dist/utils/errors"; import { createLazyProxy } from "@stackframe/stack-shared/dist/utils/proxies"; -export const userPermissionsCrudHandlers = createLazyProxy(() => createCrudHandlers(userPermissionsCrud, { +export const projectPermissionsCrudHandlers = createLazyProxy(() => createCrudHandlers(projectPermissionsCrud, { querySchema: yupObject({ user_id: userIdOrMeSchema.optional().meta({ openapiField: { onlyShowInOperations: [ 'List' ], description: 'Filter with the user ID. If set, only the permissions this user has will be returned. Client request must set `user_id=me`', exampleValue: 'me' } }), permission_id: teamPermissionDefinitionIdSchema.optional().meta({ openapiField: { onlyShowInOperations: [ 'List' ], description: 'Filter with the permission ID. If set, only the permissions with this specific ID will be returned', exampleValue: '16399452-c4f3-4554-8e44-c2d67bb60360' } }), @@ -31,7 +31,7 @@ export const userPermissionsCrudHandlers = createLazyProxy(() => createCrudHandl }); }); - runAsynchronouslyAndWaitUntil(sendUserPermissionCreatedWebhook({ + runAsynchronouslyAndWaitUntil(sendProjectPermissionCreatedWebhook({ projectId: auth.project.id, data: { id: params.permission_id, @@ -58,7 +58,7 @@ export const userPermissionsCrudHandlers = createLazyProxy(() => createCrudHandl }); }); - runAsynchronouslyAndWaitUntil(sendUserPermissionDeletedWebhook({ + runAsynchronouslyAndWaitUntil(sendProjectPermissionDeletedWebhook({ projectId: auth.project.id, data: { id: params.permission_id, diff --git a/apps/backend/src/app/api/latest/project-permissions/route.tsx b/apps/backend/src/app/api/latest/project-permissions/route.tsx index b8a525185..7ce3c4ab3 100644 --- a/apps/backend/src/app/api/latest/project-permissions/route.tsx +++ b/apps/backend/src/app/api/latest/project-permissions/route.tsx @@ -1,3 +1,3 @@ -import { userPermissionsCrudHandlers } from "./crud"; +import { projectPermissionsCrudHandlers } from "./crud"; -export const GET = userPermissionsCrudHandlers.listHandler; +export const GET = projectPermissionsCrudHandlers.listHandler; diff --git a/apps/backend/src/lib/permissions.tsx b/apps/backend/src/lib/permissions.tsx index 9ccea130f..a3429dcb5 100644 --- a/apps/backend/src/lib/permissions.tsx +++ b/apps/backend/src/lib/permissions.tsx @@ -1,7 +1,7 @@ import { TeamSystemPermission as DBTeamSystemPermission, Prisma } from "@prisma/client"; import { KnownErrors } from "@stackframe/stack-shared"; import { TeamPermissionDefinitionsCrud, TeamPermissionsCrud } from "@stackframe/stack-shared/dist/interface/crud/team-permissions"; -import { UserPermissionsCrud } from "@stackframe/stack-shared/dist/interface/crud/user-permissions"; +import { ProjectPermissionsCrud } from "@stackframe/stack-shared/dist/interface/crud/project-permissions"; import { groupBy } from "@stackframe/stack-shared/dist/utils/arrays"; import { StackAssertionError, throwErr } from "@stackframe/stack-shared/dist/utils/errors"; import { stringCompare, typedToLowercase, typedToUppercase } from "@stackframe/stack-shared/dist/utils/strings"; @@ -485,7 +485,7 @@ export async function listUserPermissions( permissionId?: string, recursive: boolean, } -): Promise { +): Promise { const permissionDefs = await listPermissionDefinitions(tx, "PROJECT", options.tenancy); const permissionsMap = new Map(permissionDefs.map(p => [p.id, p])); const results = await tx.projectUserDirectPermission.findMany({ diff --git a/apps/backend/src/lib/webhooks.tsx b/apps/backend/src/lib/webhooks.tsx index 93bfd2e60..cac56608e 100644 --- a/apps/backend/src/lib/webhooks.tsx +++ b/apps/backend/src/lib/webhooks.tsx @@ -1,8 +1,8 @@ +import { projectPermissionCreatedWebhookEvent, projectPermissionDeletedWebhookEvent } from "@stackframe/stack-shared/dist/interface/crud/project-permissions"; import { teamMembershipCreatedWebhookEvent, teamMembershipDeletedWebhookEvent } from "@stackframe/stack-shared/dist/interface/crud/team-memberships"; import { teamPermissionCreatedWebhookEvent, teamPermissionDeletedWebhookEvent } from "@stackframe/stack-shared/dist/interface/crud/team-permissions"; import { teamCreatedWebhookEvent, teamDeletedWebhookEvent, teamUpdatedWebhookEvent } from "@stackframe/stack-shared/dist/interface/crud/teams"; import { userCreatedWebhookEvent, userDeletedWebhookEvent, userUpdatedWebhookEvent } from "@stackframe/stack-shared/dist/interface/crud/users"; -import { userPermissionCreatedWebhookEvent, userPermissionDeletedWebhookEvent } from "@stackframe/stack-shared/dist/interface/crud/user-permissions"; import { WebhookEvent } from "@stackframe/stack-shared/dist/interface/webhooks"; import { getEnvVariable } from "@stackframe/stack-shared/dist/utils/env"; import { StackAssertionError, captureError } from "@stackframe/stack-shared/dist/utils/errors"; @@ -74,5 +74,5 @@ export const sendTeamMembershipCreatedWebhook = createWebhookSender(teamMembersh export const sendTeamMembershipDeletedWebhook = createWebhookSender(teamMembershipDeletedWebhookEvent); export const sendTeamPermissionCreatedWebhook = createWebhookSender(teamPermissionCreatedWebhookEvent); export const sendTeamPermissionDeletedWebhook = createWebhookSender(teamPermissionDeletedWebhookEvent); -export const sendUserPermissionCreatedWebhook = createWebhookSender(userPermissionCreatedWebhookEvent); -export const sendUserPermissionDeletedWebhook = createWebhookSender(userPermissionDeletedWebhookEvent); +export const sendProjectPermissionCreatedWebhook = createWebhookSender(projectPermissionCreatedWebhookEvent); +export const sendProjectPermissionDeletedWebhook = createWebhookSender(projectPermissionDeletedWebhookEvent); diff --git a/apps/e2e/tests/backend/endpoints/api/v1/user-permission-definitions.test.ts b/apps/e2e/tests/backend/endpoints/api/v1/project-permission-definitions.test.ts similarity index 86% rename from apps/e2e/tests/backend/endpoints/api/v1/user-permission-definitions.test.ts rename to apps/e2e/tests/backend/endpoints/api/v1/project-permission-definitions.test.ts index 8bbb228af..c5fe0f7f8 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/user-permission-definitions.test.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/project-permission-definitions.test.ts @@ -6,7 +6,7 @@ it("lists all the user permissions", async ({ expect }) => { backendContext.set({ projectKeys: InternalProjectKeys }); const { adminAccessToken } = await Project.createAndGetAdminToken(); - const response = await niceBackendFetch(`/api/v1/user-permission-definitions`, { + const response = await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "GET", headers: { @@ -29,7 +29,7 @@ it("creates, updates, and deletes a new user permission", async ({ expect }) => backendContext.set({ projectKeys: InternalProjectKeys }); const { adminAccessToken } = await Project.createAndGetAdminToken(); - const response1 = await niceBackendFetch(`/api/v1/user-permission-definitions`, { + const response1 = await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "POST", body: { @@ -51,7 +51,7 @@ it("creates, updates, and deletes a new user permission", async ({ expect }) => `); // create another permission with contained permissions - const response2 = await niceBackendFetch(`/api/v1/user-permission-definitions`, { + const response2 = await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "POST", body: { @@ -74,7 +74,7 @@ it("creates, updates, and deletes a new user permission", async ({ expect }) => `); // test recursive case - const response3 = await niceBackendFetch(`/api/v1/user-permission-definitions`, { + const response3 = await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "POST", body: { @@ -98,7 +98,7 @@ it("creates, updates, and deletes a new user permission", async ({ expect }) => `); // list all permissions again - const response4 = await niceBackendFetch(`/api/v1/user-permission-definitions`, { + const response4 = await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "GET", headers: { @@ -130,7 +130,7 @@ it("creates, updates, and deletes a new user permission", async ({ expect }) => `); // delete the permission - const response5 = await niceBackendFetch(`/api/v1/user-permission-definitions/p1`, { + const response5 = await niceBackendFetch(`/api/v1/project-permission-definitions/p1`, { accessType: "admin", method: "DELETE", headers: { @@ -146,7 +146,7 @@ it("creates, updates, and deletes a new user permission", async ({ expect }) => `); // list all permissions again - const response6 = await niceBackendFetch(`/api/v1/user-permission-definitions`, { + const response6 = await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "GET", headers: { diff --git a/apps/e2e/tests/backend/endpoints/api/v1/user-permissions.test.ts b/apps/e2e/tests/backend/endpoints/api/v1/project-permissions.test.ts similarity index 89% rename from apps/e2e/tests/backend/endpoints/api/v1/user-permissions.test.ts rename to apps/e2e/tests/backend/endpoints/api/v1/project-permissions.test.ts index abf593d49..28d92df94 100644 --- a/apps/e2e/tests/backend/endpoints/api/v1/user-permissions.test.ts +++ b/apps/e2e/tests/backend/endpoints/api/v1/project-permissions.test.ts @@ -5,7 +5,7 @@ import { ApiKey, Auth, InternalProjectKeys, Project, Team, Webhook, backendConte it("is not allowed to list permissions from the other users on the client", async ({ expect }) => { await Auth.Otp.signIn(); - const response = await niceBackendFetch(`/api/v1/user-permissions`, { + const response = await niceBackendFetch(`/api/v1/project-permissions`, { accessType: "client", method: "GET", }); @@ -21,7 +21,7 @@ it("is not allowed to list permissions from the other users on the client", asyn it("is not allowed to grant non-existing permission to a user on the server", async ({ expect }) => { const { userId } = await Auth.Otp.signIn(); - const response = await niceBackendFetch(`/api/v1/user-permissions/${userId}/does_not_exist`, { + const response = await niceBackendFetch(`/api/v1/project-permissions/${userId}/does_not_exist`, { accessType: "server", method: "POST", body: {}, @@ -47,7 +47,7 @@ it("can create a new permission and grant it to a user on the server", async ({ const { adminAccessToken } = await Project.createAndGetAdminToken({ config: { magic_link_enabled: true } }); // create a permission child - await niceBackendFetch(`/api/v1/user-permission-definitions`, { + await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "POST", body: { @@ -60,7 +60,7 @@ it("can create a new permission and grant it to a user on the server", async ({ }); // create a permission parent - await niceBackendFetch(`/api/v1/user-permission-definitions`, { + await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "POST", body: { @@ -78,7 +78,7 @@ it("can create a new permission and grant it to a user on the server", async ({ const { userId } = await Auth.Password.signUpWithEmail({ password: 'test1234' }); // list current permissions - const response1 = await niceBackendFetch(`/api/v1/user-permissions?user_id=me`, { + const response1 = await niceBackendFetch(`/api/v1/project-permissions?user_id=me`, { accessType: "client", method: "GET", }); @@ -94,7 +94,7 @@ it("can create a new permission and grant it to a user on the server", async ({ `); // grant new permission - const response2 = await niceBackendFetch(`/api/v1/user-permissions/${userId}/parent`, { + const response2 = await niceBackendFetch(`/api/v1/project-permissions/${userId}/parent`, { accessType: "server", method: "POST", body: {}, @@ -111,7 +111,7 @@ it("can create a new permission and grant it to a user on the server", async ({ `); // list current permissions (should have the new permission) - const response3 = await niceBackendFetch(`/api/v1/user-permissions?user_id=me`, { + const response3 = await niceBackendFetch(`/api/v1/project-permissions?user_id=me`, { accessType: "client", method: "GET", }); @@ -136,7 +136,7 @@ it("can customize default user permissions", async ({ expect }) => { await Auth.Otp.signIn(); const { adminAccessToken } = await Project.createAndGetAdminToken(); - const response1 = await niceBackendFetch(`/api/v1/user-permission-definitions`, { + const response1 = await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "POST", body: { @@ -202,7 +202,7 @@ it("can customize default user permissions", async ({ expect }) => { // sign up a new user const { userId } = await Auth.Password.signUpWithEmail({ password: 'test1234' }); // list permissions for the new user - const response3 = await niceBackendFetch(`/api/v1/user-permissions?user_id=${userId}`, { + const response3 = await niceBackendFetch(`/api/v1/project-permissions?user_id=${userId}`, { accessType: "client", method: "GET", }); @@ -228,13 +228,13 @@ it("should trigger user permission webhook when a permission is granted to a use const { userId } = await Auth.Otp.signIn(); - await niceBackendFetch(`/api/v1/user-permission-definitions`, { + await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "POST", body: { id: 'test_permission' }, }); - const grantPermissionResponse = await niceBackendFetch(`/api/v1/user-permissions/${userId}/test_permission`, { + const grantPermissionResponse = await niceBackendFetch(`/api/v1/project-permissions/${userId}/test_permission`, { accessType: "server", method: "POST", body: {}, @@ -270,14 +270,14 @@ it("should trigger user permission webhook when a permission is revoked from a u const { userId } = await Auth.Otp.signIn(); - await niceBackendFetch(`/api/v1/user-permission-definitions`, { + await niceBackendFetch(`/api/v1/project-permission-definitions`, { accessType: "admin", method: "POST", body: { id: 'test_permission' }, }); // First grant the permission - const grantPermissionResponse = await niceBackendFetch(`/api/v1/user-permissions/${userId}/test_permission`, { + const grantPermissionResponse = await niceBackendFetch(`/api/v1/project-permissions/${userId}/test_permission`, { accessType: "server", method: "POST", body: {}, @@ -286,7 +286,7 @@ it("should trigger user permission webhook when a permission is revoked from a u expect(grantPermissionResponse.status).toBe(201); // Then revoke the permission - const revokePermissionResponse = await niceBackendFetch(`/api/v1/user-permissions/${userId}/test_permission`, { + const revokePermissionResponse = await niceBackendFetch(`/api/v1/project-permissions/${userId}/test_permission`, { accessType: "server", method: "DELETE", }); diff --git a/packages/stack-shared/src/interface/adminInterface.ts b/packages/stack-shared/src/interface/adminInterface.ts index d69040f90..5ed0dd02d 100644 --- a/packages/stack-shared/src/interface/adminInterface.ts +++ b/packages/stack-shared/src/interface/adminInterface.ts @@ -2,10 +2,10 @@ 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 { UserPermissionDefinitionsCrud } from "./crud/user-permissions"; import { ServerAuthApplicationOptions, StackServerInterface } from "./serverInterface"; export type AdminAuthApplicationOptions = ServerAuthApplicationOptions &( @@ -194,15 +194,15 @@ export class StackAdminInterface extends StackServerInterface { ); } - async listUserPermissionDefinitions(): Promise { - const response = await this.sendAdminRequest(`/user-permission-definitions`, {}, null); - const result = await response.json() as UserPermissionDefinitionsCrud['Admin']['List']; + async listProjectPermissionDefinitions(): Promise { + const response = await this.sendAdminRequest(`/project-permission-definitions`, {}, null); + const result = await response.json() as ProjectPermissionDefinitionsCrud['Admin']['List']; return result.items; } - async createUserPermissionDefinition(data: UserPermissionDefinitionsCrud['Admin']['Create']): Promise { + async createProjectPermissionDefinition(data: ProjectPermissionDefinitionsCrud['Admin']['Create']): Promise { const response = await this.sendAdminRequest( - "/user-permission-definitions", + "/project-permission-definitions", { method: "POST", headers: { @@ -215,9 +215,9 @@ export class StackAdminInterface extends StackServerInterface { return await response.json(); } - async updateUserPermissionDefinition(permissionId: string, data: UserPermissionDefinitionsCrud['Admin']['Update']): Promise { + async updateProjectPermissionDefinition(permissionId: string, data: ProjectPermissionDefinitionsCrud['Admin']['Update']): Promise { const response = await this.sendAdminRequest( - `/user-permission-definitions/${permissionId}`, + `/project-permission-definitions/${permissionId}`, { method: "PATCH", headers: { @@ -230,9 +230,9 @@ export class StackAdminInterface extends StackServerInterface { return await response.json(); } - async deleteUserPermissionDefinition(permissionId: string): Promise { + async deleteProjectPermissionDefinition(permissionId: string): Promise { await this.sendAdminRequest( - `/user-permission-definitions/${permissionId}`, + `/project-permission-definitions/${permissionId}`, { method: "DELETE" }, null, ); diff --git a/packages/stack-shared/src/interface/crud/project-permissions.ts b/packages/stack-shared/src/interface/crud/project-permissions.ts new file mode 100644 index 000000000..68d5b1997 --- /dev/null +++ b/packages/stack-shared/src/interface/crud/project-permissions.ts @@ -0,0 +1,118 @@ +import { CrudTypeOf, createCrud } from "../../crud"; +import * as schemaFields from "../../schema-fields"; +import { yupMixed, yupObject } from "../../schema-fields"; +import { WebhookEvent } from "../webhooks"; + +// =============== Project permissions ================= + +export const projectPermissionsCrudClientReadSchema = yupObject({ + id: schemaFields.teamPermissionDefinitionIdSchema.defined(), + user_id: schemaFields.userIdSchema.defined(), +}).defined(); + +export const projectPermissionsCrudServerCreateSchema = yupObject({ +}).defined(); + +export const projectPermissionsCrudServerDeleteSchema = yupMixed(); + +export const projectPermissionsCrud = createCrud({ + clientReadSchema: projectPermissionsCrudClientReadSchema, + serverCreateSchema: projectPermissionsCrudServerCreateSchema, + serverDeleteSchema: projectPermissionsCrudServerDeleteSchema, + docs: { + clientList: { + summary: "List project permissions", + description: "List global permissions of the current user. `user_id=me` must be set for client requests. `(user_id, permission_id)` together uniquely identify a permission.", + tags: ["Permissions"], + }, + serverList: { + summary: "List project permissions", + description: "Query and filter the permission with `user_id` and `permission_id`. `(user_id, permission_id)` together uniquely identify a permission.", + tags: ["Permissions"], + }, + serverCreate: { + summary: "Grant a global permission to a user", + description: "Grant a global permission to a user (the permission must be created first on the Stack dashboard)", + tags: ["Permissions"], + }, + serverDelete: { + summary: "Revoke a global permission from a user", + description: "Revoke a global permission from a user", + tags: ["Permissions"], + }, + }, +}); +export type ProjectPermissionsCrud = CrudTypeOf; + +export const projectPermissionCreatedWebhookEvent = { + type: "project_permission.created", + schema: projectPermissionsCrud.server.readSchema, + metadata: { + summary: "Project Permission Created", + description: "This event is triggered when a project permission is created.", + tags: ["Users"], + }, +} satisfies WebhookEvent; + +export const projectPermissionDeletedWebhookEvent = { + type: "project_permission.deleted", + schema: projectPermissionsCrud.server.readSchema, + metadata: { + summary: "Project Permission Deleted", + description: "This event is triggered when a project permission is deleted.", + tags: ["Users"], + }, +} satisfies WebhookEvent; + +// =============== Project permission definitions ================= + +export const projectPermissionDefinitionsCrudAdminReadSchema = yupObject({ + id: schemaFields.teamPermissionDefinitionIdSchema.defined(), + description: schemaFields.teamPermissionDescriptionSchema.optional(), + contained_permission_ids: schemaFields.containedPermissionIdsSchema.defined(), +}).defined(); + +export const projectPermissionDefinitionsCrudAdminCreateSchema = yupObject({ + id: schemaFields.customTeamPermissionDefinitionIdSchema.defined(), + description: schemaFields.teamPermissionDescriptionSchema.optional(), + contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional(), +}).defined(); + +export const projectPermissionDefinitionsCrudAdminUpdateSchema = yupObject({ + id: schemaFields.customTeamPermissionDefinitionIdSchema.optional(), + description: schemaFields.teamPermissionDescriptionSchema.optional(), + contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional(), +}).defined(); + +export const projectPermissionDefinitionsCrudAdminDeleteSchema = yupMixed(); + +export const projectPermissionDefinitionsCrud = createCrud({ + adminReadSchema: projectPermissionDefinitionsCrudAdminReadSchema, + adminCreateSchema: projectPermissionDefinitionsCrudAdminCreateSchema, + adminUpdateSchema: projectPermissionDefinitionsCrudAdminUpdateSchema, + adminDeleteSchema: projectPermissionDefinitionsCrudAdminDeleteSchema, + docs: { + adminList: { + summary: "List project permission definitions", + description: "Query and filter project permission definitions (the equivalent of listing permissions on the Stack dashboard)", + tags: ["Permissions"], + }, + adminCreate: { + summary: "Create a new project permission definition", + description: "Create a new project permission definition (the equivalent of creating a new permission on the Stack dashboard)", + tags: ["Permissions"], + }, + adminUpdate: { + summary: "Update a project permission definition", + description: "Update a project permission definition (the equivalent of updating a permission on the Stack dashboard)", + tags: ["Permissions"], + }, + adminDelete: { + summary: "Delete a project permission definition", + description: "Delete a project permission definition (the equivalent of deleting a permission on the Stack dashboard)", + tags: ["Permissions"], + }, + }, +}); + +export type ProjectPermissionDefinitionsCrud = CrudTypeOf; diff --git a/packages/stack-shared/src/interface/crud/user-permissions.ts b/packages/stack-shared/src/interface/crud/user-permissions.ts deleted file mode 100644 index f8c869413..000000000 --- a/packages/stack-shared/src/interface/crud/user-permissions.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { CrudTypeOf, createCrud } from "../../crud"; -import * as schemaFields from "../../schema-fields"; -import { yupMixed, yupObject } from "../../schema-fields"; -import { WebhookEvent } from "../webhooks"; - -// =============== User permissions ================= - -export const userPermissionsCrudClientReadSchema = yupObject({ - id: schemaFields.teamPermissionDefinitionIdSchema.defined(), - user_id: schemaFields.userIdSchema.defined(), -}).defined(); - -export const userPermissionsCrudServerCreateSchema = yupObject({ -}).defined(); - -export const userPermissionsCrudServerDeleteSchema = yupMixed(); - -export const userPermissionsCrud = createCrud({ - clientReadSchema: userPermissionsCrudClientReadSchema, - serverCreateSchema: userPermissionsCrudServerCreateSchema, - serverDeleteSchema: userPermissionsCrudServerDeleteSchema, - docs: { - clientList: { - summary: "List user permissions", - description: "List global permissions of the current user. `user_id=me` must be set for client requests. `(user_id, permission_id)` together uniquely identify a permission.", - tags: ["Permissions"], - }, - serverList: { - summary: "List user permissions", - description: "Query and filter the permission with `user_id` and `permission_id`. `(user_id, permission_id)` together uniquely identify a permission.", - tags: ["Permissions"], - }, - serverCreate: { - summary: "Grant a global permission to a user", - description: "Grant a global permission to a user (the permission must be created first on the Stack dashboard)", - tags: ["Permissions"], - }, - serverDelete: { - summary: "Revoke a global permission from a user", - description: "Revoke a global permission from a user", - tags: ["Permissions"], - }, - }, -}); -export type UserPermissionsCrud = CrudTypeOf; - -export const userPermissionCreatedWebhookEvent = { - type: "user_permission.created", - schema: userPermissionsCrud.server.readSchema, - metadata: { - summary: "User Permission Created", - description: "This event is triggered when a user permission is created.", - tags: ["Users"], - }, -} satisfies WebhookEvent; - -export const userPermissionDeletedWebhookEvent = { - type: "user_permission.deleted", - schema: userPermissionsCrud.server.readSchema, - metadata: { - summary: "User Permission Deleted", - description: "This event is triggered when a user permission is deleted.", - tags: ["Users"], - }, -} satisfies WebhookEvent; - -// =============== User permission definitions ================= - -export const userPermissionDefinitionsCrudAdminReadSchema = yupObject({ - id: schemaFields.teamPermissionDefinitionIdSchema.defined(), - description: schemaFields.teamPermissionDescriptionSchema.optional(), - contained_permission_ids: schemaFields.containedPermissionIdsSchema.defined(), -}).defined(); - -export const userPermissionDefinitionsCrudAdminCreateSchema = yupObject({ - id: schemaFields.customTeamPermissionDefinitionIdSchema.defined(), - description: schemaFields.teamPermissionDescriptionSchema.optional(), - contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional(), -}).defined(); - -export const userPermissionDefinitionsCrudAdminUpdateSchema = yupObject({ - id: schemaFields.customTeamPermissionDefinitionIdSchema.optional(), - description: schemaFields.teamPermissionDescriptionSchema.optional(), - contained_permission_ids: schemaFields.containedPermissionIdsSchema.optional(), -}).defined(); - -export const userPermissionDefinitionsCrudAdminDeleteSchema = yupMixed(); - -export const userPermissionDefinitionsCrud = createCrud({ - adminReadSchema: userPermissionDefinitionsCrudAdminReadSchema, - adminCreateSchema: userPermissionDefinitionsCrudAdminCreateSchema, - adminUpdateSchema: userPermissionDefinitionsCrudAdminUpdateSchema, - adminDeleteSchema: userPermissionDefinitionsCrudAdminDeleteSchema, - docs: { - adminList: { - summary: "List user permission definitions", - description: "Query and filter user permission definitions (the equivalent of listing permissions on the Stack dashboard)", - tags: ["Permissions"], - }, - adminCreate: { - summary: "Create a new user permission definition", - description: "Create a new user permission definition (the equivalent of creating a new permission on the Stack dashboard)", - tags: ["Permissions"], - }, - adminUpdate: { - summary: "Update a user permission definition", - description: "Update a user permission definition (the equivalent of updating a permission on the Stack dashboard)", - tags: ["Permissions"], - }, - adminDelete: { - summary: "Delete a user permission definition", - description: "Delete a user permission definition (the equivalent of deleting a permission on the Stack dashboard)", - tags: ["Permissions"], - }, - }, -}); - -export type UserPermissionDefinitionsCrud = CrudTypeOf;