diff --git a/apps/sim/.env.example b/apps/sim/.env.example
index f5d05f0ac23..c8b8583d103 100644
--- a/apps/sim/.env.example
+++ b/apps/sim/.env.example
@@ -214,7 +214,6 @@ CRON_SECRET=your_cron_secret # Use `openssl rand -hex 32` to generate. Authentic
# FORKING_ENABLED= # Workspace forks
# CREDENTIAL_GROUPS= # Enterprise managed OAuth collections
# TABLE_ROW_TTL= # Table TTL columns and expired-row cleanup
-# PERMISSION_ACCESS_REQUESTS_ENABLED= # Global access-request rollout; organizations may opt out
# KNOWLEDGE_MEMBER_ACCESS= # Per-member knowledge connectors and hybrid-by-default retrieval
# ORGANIZATIONS_ENABLED= / NEXT_PUBLIC_ORGANIZATIONS_ENABLED= # Organizations only
diff --git a/apps/sim/app/access-requests/loading.tsx b/apps/sim/app/access-requests/loading.tsx
index 4eb54fb68e8..5ee4cac94d1 100644
--- a/apps/sim/app/access-requests/loading.tsx
+++ b/apps/sim/app/access-requests/loading.tsx
@@ -1,4 +1,4 @@
-import { AccessRequestsLoading } from '@/components/access-requests/access-requests-loading'
+import { AccessRequestsLoading } from '@/ee/access-requests/components/access-requests-loading'
export default function Loading() {
return
diff --git a/apps/sim/app/access-requests/page.test.tsx b/apps/sim/app/access-requests/page.test.tsx
index f1f50b8cae5..9ea92ec6dd5 100644
--- a/apps/sim/app/access-requests/page.test.tsx
+++ b/apps/sim/app/access-requests/page.test.tsx
@@ -4,8 +4,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
const { redirect } = vi.hoisted(() => ({ redirect: vi.fn() }))
vi.mock('next/navigation', () => ({ redirect }))
-vi.mock('@/components/access-requests/my-access-requests', () => ({ MyAccessRequests: () => null }))
-vi.mock('@/components/access-requests/organization-access-requests', () => ({
+vi.mock('@/ee/access-requests/components/my-access-requests', () => ({
+ MyAccessRequests: () => null,
+}))
+vi.mock('@/ee/access-requests/components/organization-access-requests', () => ({
OrganizationAccessRequests: () => null,
}))
diff --git a/apps/sim/app/access-requests/page.tsx b/apps/sim/app/access-requests/page.tsx
index a3c90a5ec65..bca8ec035cd 100644
--- a/apps/sim/app/access-requests/page.tsx
+++ b/apps/sim/app/access-requests/page.tsx
@@ -3,14 +3,14 @@ import { ChipLink } from '@sim/emcn'
import type { Metadata } from 'next'
import { redirect } from 'next/navigation'
import { createSearchParamsCache, createSerializer } from 'nuqs/server'
-import { AccessRequestsLoading } from '@/components/access-requests/access-requests-loading'
-import { MyAccessRequests } from '@/components/access-requests/my-access-requests'
-import { OrganizationAccessRequests } from '@/components/access-requests/organization-access-requests'
-import { accessRequestEntrySearchParams } from '@/components/access-requests/search-params'
import { EmptyState } from '@/components/empty-state/empty-state'
import { getSession } from '@/lib/auth'
import { WORKSPACES_PATH } from '@/lib/navigation/paths'
import { buildAuthCrossLink } from '@/app/(auth)/auth-redirect'
+import { AccessRequestsLoading } from '@/ee/access-requests/components/access-requests-loading'
+import { MyAccessRequests } from '@/ee/access-requests/components/my-access-requests'
+import { OrganizationAccessRequests } from '@/ee/access-requests/components/organization-access-requests'
+import { accessRequestEntrySearchParams } from '@/ee/access-requests/components/search-params'
export const metadata: Metadata = {
title: 'Access requests',
diff --git a/apps/sim/app/api/access-requests/[requestId]/cancel/route.ts b/apps/sim/app/api/access-requests/[requestId]/cancel/route.ts
index c887c12d619..f14ddb2bbfa 100644
--- a/apps/sim/app/api/access-requests/[requestId]/cancel/route.ts
+++ b/apps/sim/app/api/access-requests/[requestId]/cancel/route.ts
@@ -5,8 +5,8 @@ import {
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
-import { cancelAccessRequest } from '@/lib/permission-access-requests/application/requests'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
+import { cancelAccessRequest } from '@/ee/access-requests/lib/application/requests'
export const POST = defineInternalJsonRoute({
contract: cancelAccessRequestContract,
diff --git a/apps/sim/app/api/access-requests/discovery/route.ts b/apps/sim/app/api/access-requests/discovery/route.ts
index 4e0e645fc41..d01e371eeb9 100644
--- a/apps/sim/app/api/access-requests/discovery/route.ts
+++ b/apps/sim/app/api/access-requests/discovery/route.ts
@@ -5,8 +5,8 @@ import {
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
-import { discoverAccessRequests } from '@/lib/permission-access-requests/application/requests'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
+import { discoverAccessRequests } from '@/ee/access-requests/lib/application/requests'
export const GET = defineInternalJsonRoute({
contract: discoverAccessRequestsContract,
diff --git a/apps/sim/app/api/access-requests/route.ts b/apps/sim/app/api/access-requests/route.ts
index 74e2bd961c8..9df80669571 100644
--- a/apps/sim/app/api/access-requests/route.ts
+++ b/apps/sim/app/api/access-requests/route.ts
@@ -8,11 +8,11 @@ import {
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
import {
createAccessRequest,
listMyAccessRequests,
-} from '@/lib/permission-access-requests/application/requests'
+} from '@/ee/access-requests/lib/application/requests'
export const GET = defineInternalJsonRoute({
contract: listMyAccessRequestsContract,
diff --git a/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/preview/route.ts b/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/preview/route.ts
index c4ba646b057..e5bfd549838 100644
--- a/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/preview/route.ts
+++ b/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/preview/route.ts
@@ -5,8 +5,8 @@ import {
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
-import { previewAccessRequest } from '@/lib/permission-access-requests/application/review'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
+import { previewAccessRequest } from '@/ee/access-requests/lib/application/review'
export const GET = defineInternalJsonRoute({
contract: previewAccessRequestContract,
diff --git a/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/resolve/route.ts b/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/resolve/route.ts
index 0bc389ec7e9..b0e477a8b2c 100644
--- a/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/resolve/route.ts
+++ b/apps/sim/app/api/organizations/[id]/access-requests/[requestId]/resolve/route.ts
@@ -5,8 +5,8 @@ import {
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
-import { resolveAccessRequest } from '@/lib/permission-access-requests/application/review'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
+import { resolveAccessRequest } from '@/ee/access-requests/lib/application/review'
export const POST = defineInternalJsonRoute({
contract: resolveAccessRequestContract,
diff --git a/apps/sim/app/api/organizations/[id]/access-requests/route.ts b/apps/sim/app/api/organizations/[id]/access-requests/route.ts
index f68a80694bb..dae84fefaa7 100644
--- a/apps/sim/app/api/organizations/[id]/access-requests/route.ts
+++ b/apps/sim/app/api/organizations/[id]/access-requests/route.ts
@@ -5,8 +5,8 @@ import {
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
-import { listOrganizationAccessRequests } from '@/lib/permission-access-requests/application/requests'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
+import { listOrganizationAccessRequests } from '@/ee/access-requests/lib/application/requests'
export const GET = defineInternalJsonRoute({
contract: listOrganizationAccessRequestsContract,
diff --git a/apps/sim/app/api/organizations/[id]/access-requests/settings/route.ts b/apps/sim/app/api/organizations/[id]/access-requests/settings/route.ts
index 6f4ceec0c09..00196e574a6 100644
--- a/apps/sim/app/api/organizations/[id]/access-requests/settings/route.ts
+++ b/apps/sim/app/api/organizations/[id]/access-requests/settings/route.ts
@@ -8,11 +8,11 @@ import {
internalRateLimits,
internalSessionAuth,
} from '@/lib/api/server/routes'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
import {
getAccessRequestSettings,
updateAccessRequestSettings,
-} from '@/lib/permission-access-requests/application/requests'
+} from '@/ee/access-requests/lib/application/requests'
export const GET = defineInternalJsonRoute({
contract: getAccessRequestSettingsContract,
diff --git a/apps/sim/app/workspace/[workspaceId]/access-requests/loading.tsx b/apps/sim/app/workspace/[workspaceId]/access-requests/loading.tsx
index 4eb54fb68e8..5ee4cac94d1 100644
--- a/apps/sim/app/workspace/[workspaceId]/access-requests/loading.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/access-requests/loading.tsx
@@ -1,4 +1,4 @@
-import { AccessRequestsLoading } from '@/components/access-requests/access-requests-loading'
+import { AccessRequestsLoading } from '@/ee/access-requests/components/access-requests-loading'
export default function Loading() {
return
diff --git a/apps/sim/app/workspace/[workspaceId]/access-requests/page.tsx b/apps/sim/app/workspace/[workspaceId]/access-requests/page.tsx
index b3d49e88885..fa84a020a79 100644
--- a/apps/sim/app/workspace/[workspaceId]/access-requests/page.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/access-requests/page.tsx
@@ -1,7 +1,7 @@
import { Suspense } from 'react'
import type { Metadata } from 'next'
-import { AccessRequestsLoading } from '@/components/access-requests/access-requests-loading'
-import { MyAccessRequests } from '@/components/access-requests/my-access-requests'
+import { AccessRequestsLoading } from '@/ee/access-requests/components/access-requests-loading'
+import { MyAccessRequests } from '@/ee/access-requests/components/my-access-requests'
export const metadata: Metadata = { title: 'My access requests' }
diff --git a/apps/sim/app/workspace/[workspaceId]/files/files.tsx b/apps/sim/app/workspace/[workspaceId]/files/files.tsx
index 610456cd742..5c98c2aaeba 100644
--- a/apps/sim/app/workspace/[workspaceId]/files/files.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/files/files.tsx
@@ -24,7 +24,6 @@ import { getErrorMessage, toError } from '@sim/utils/errors'
import { useParams, useRouter } from 'next/navigation'
import { useQueryStates } from 'nuqs'
import { usePostHog } from 'posthog-js/react'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { getDocumentIcon } from '@/components/icons/document-icons'
import { useLimitUpgradeToast } from '@/lib/billing/client'
import { captureEvent } from '@/lib/posthog/client'
@@ -137,6 +136,7 @@ import {
} from '@/app/workspace/[workspaceId]/files/untitled-title'
import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
import { usePinItem, usePinnedIds, useUnpinItem } from '@/hooks/queries/pinned-items'
import { useWorkspaceMembersQuery, type WorkspaceMember } from '@/hooks/queries/workspace'
import {
diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx
index f68a9e8bcfb..c96110df49f 100644
--- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx
@@ -5,7 +5,6 @@ import { cn, Expandable, ExpandableContent, SecretReveal, Tooltip, toast } from
import { ArrowRight, Check, ChevronDown, SquareArrowUpRight, TerminalWindow } from '@sim/emcn/icons'
import { isRecordLike } from '@sim/utils/object'
import { useParams } from 'next/navigation'
-import { MemberLimitRequestAction } from '@/components/access-requests/member-limit-request-action'
import { useSession } from '@/lib/auth/auth-client'
import { buildHostedUpgradeUrl, HOSTED_BILLING_SETTINGS_URL } from '@/lib/billing/upgrade-reasons'
import { canManageWorkspaceBilling } from '@/lib/billing/workspace-permissions'
@@ -62,6 +61,7 @@ import { useServiceAccountConnectTarget } from '@/app/workspace/[workspaceId]/in
import { useWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { BrandIcon } from '@/blocks/brand-icon'
+import { MemberLimitRequestAction } from '@/ee/access-requests/components/member-limit-request-action'
import {
useUpdateWorkspaceCredential,
useWorkspaceCredential,
diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/usage-upgrade-display.test.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/usage-upgrade-display.test.tsx
index 77a2ea45758..340b39668d4 100644
--- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/usage-upgrade-display.test.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/usage-upgrade-display.test.tsx
@@ -24,7 +24,7 @@ vi.mock('@/app/workspace/[workspaceId]/providers/workspace-host-provider', () =>
vi.mock('@/hooks/use-settings-navigation', () => ({
useSettingsNavigation: () => ({ getSettingsHref: () => '/settings/billing' }),
}))
-vi.mock('@/components/access-requests/member-limit-request-action', () => ({
+vi.mock('@/ee/access-requests/components/member-limit-request-action', () => ({
MemberLimitRequestAction: () => ,
}))
diff --git a/apps/sim/app/workspace/[workspaceId]/home/home.tsx b/apps/sim/app/workspace/[workspaceId]/home/home.tsx
index ff7515d1711..56846b001d5 100644
--- a/apps/sim/app/workspace/[workspaceId]/home/home.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/home/home.tsx
@@ -19,7 +19,6 @@ import { useQueryClient } from '@tanstack/react-query'
import { useParams, useRouter } from 'next/navigation'
import { useQueryState } from 'nuqs'
import { usePostHog } from 'posthog-js/react'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { requestJson } from '@/lib/api/client/request'
import { createWorkflowContract } from '@/lib/api/contracts'
import {
@@ -45,6 +44,7 @@ import {
resolveResourceSelectionUpdate,
} from '@/app/workspace/[workspaceId]/home/resource-view-policy'
import { resourceParam, resourceUrlKeys } from '@/app/workspace/[workspaceId]/home/search-params'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
import { useFolders } from '@/hooks/queries/folders'
import { useMarkMothershipChatRead } from '@/hooks/queries/mothership-chats'
import { useWorkflows } from '@/hooks/queries/workflows'
diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/page.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/page.tsx
index 51890cea304..b363f80287d 100644
--- a/apps/sim/app/workspace/[workspaceId]/integrations/[block]/page.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/integrations/[block]/page.tsx
@@ -1,10 +1,10 @@
import { Suspense } from 'react'
import type { Metadata } from 'next'
import { notFound } from 'next/navigation'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { INTEGRATIONS } from '@/lib/integrations'
import { IntegrationBlockDetail } from '@/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail'
import { IntegrationBlockDetailFallback } from '@/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail-fallback'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
export async function generateMetadata({
params,
diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx
index 4267bc40e60..96e4ce8721e 100644
--- a/apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/integrations/connected/[credentialId]/page.tsx
@@ -1,6 +1,6 @@
import type { Metadata } from 'next'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { ConnectedCredentialDetail } from '@/app/workspace/[workspaceId]/integrations/connected/[credentialId]/connected-credential-detail'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
export const metadata: Metadata = {
title: 'Connected Integration',
diff --git a/apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx b/apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx
index a1b1ea26755..4f814f592f1 100644
--- a/apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx
@@ -13,7 +13,6 @@ import {
} from '@sim/emcn'
import { useParams } from 'next/navigation'
import { useQueryStates } from 'nuqs'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import {
blockTypeToIconMap,
formatIntegrationType,
@@ -35,6 +34,7 @@ import {
} from '@/app/workspace/[workspaceId]/integrations/search-params'
import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state'
import { SettingsResourceRow } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
import { useWorkspaceCredentials, type WorkspaceCredential } from '@/hooks/queries/credentials'
import { useDebouncedSearchSetter } from '@/hooks/use-debounced-search-setter'
import { usePermissionConfig } from '@/hooks/use-permission-config'
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx
index a49bbd1ee6d..ceb959622ba 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/page.tsx
@@ -1,8 +1,8 @@
import { Suspense } from 'react'
import type { Metadata } from 'next'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { Document } from '@/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document'
import DocumentLoading from '@/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/loading'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
interface DocumentPageProps {
params: Promise<{
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/page.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/page.tsx
index a441f86dfd8..64fd9cc7de7 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/page.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/page.tsx
@@ -1,8 +1,8 @@
import { Suspense } from 'react'
import type { Metadata } from 'next'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { KnowledgeBase } from '@/app/workspace/[workspaceId]/knowledge/[id]/base'
import KnowledgeBaseLoading from '@/app/workspace/[workspaceId]/knowledge/[id]/loading'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
interface PageProps {
params: Promise<{
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.test.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.test.tsx
index a03d3348d72..36a3e9e6b98 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.test.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.test.tsx
@@ -37,7 +37,7 @@ vi.mock('@/hooks/use-permission-config', () => ({ usePermissionConfig: () => ({
vi.mock('@/ee/access-control/hooks/permission-groups', () => ({
useUserPermissionConfig: () => ({ data: { config: {} }, isPending: false }),
}))
-vi.mock('@/hooks/queries/access-requests', () => ({
+vi.mock('@/ee/access-requests/hooks/access-requests', () => ({
useDiscoverAccessRequests: () => ({ data: { enabled: false, entries: [] }, isPending: false }),
}))
vi.mock('@/app/workspace/[workspaceId]/providers/workspace-permissions-provider', () => ({
diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx
index 2bcfc892f11..ccda6b899a9 100644
--- a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx
@@ -8,7 +8,6 @@ import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { useParams, useRouter } from 'next/navigation'
import { useQueryStates } from 'nuqs'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { MAX_KNOWLEDGE_BATCH_ITEMS } from '@/lib/knowledge/constants'
import type { KnowledgeBaseData } from '@/lib/knowledge/types'
import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state'
@@ -85,6 +84,7 @@ import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/provide
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { BrandIcon } from '@/blocks/brand-icon'
import { CONNECTOR_META_REGISTRY } from '@/connectors/registry'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
import { useKnowledgeBasesList } from '@/hooks/kb/use-knowledge'
import { useCreateFolder, useDeleteFolderMutation, useUpdateFolder } from '@/hooks/queries/folders'
import {
diff --git a/apps/sim/app/workspace/[workspaceId]/prefetch-access.test.tsx b/apps/sim/app/workspace/[workspaceId]/prefetch-access.test.tsx
index f74b6c91084..482b16115b4 100644
--- a/apps/sim/app/workspace/[workspaceId]/prefetch-access.test.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/prefetch-access.test.tsx
@@ -14,7 +14,7 @@ const mocks = vi.hoisted(() => ({
vi.mock('@/lib/permission-groups/application/read-user-config', () => ({
readUserPermissionConfig: { execute: mocks.policy },
}))
-vi.mock('@/lib/permission-access-requests/application/requests', () => ({
+vi.mock('@/ee/access-requests/lib/application/requests', () => ({
discoverAccessRequests: { execute: mocks.discovery },
}))
vi.mock('@/lib/api/client/request', () => ({ requestJson: mocks.requestJson }))
@@ -39,21 +39,21 @@ vi.mock('@sim/emcn/icons', () => ({
Upload: () => null,
BookOpen: () => null,
}))
-vi.mock('@/components/access-requests/request-access-action', () => ({
+vi.mock('@/ee/access-requests/components/request-access-action', () => ({
RequestAccessAction: ({ pendingRequestId }: { pendingRequestId: string | null }) => (
),
}))
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { ApiClientError } from '@/lib/api/client/errors'
import { getUserPermissionConfigContract } from '@/lib/api/contracts/permission-groups'
import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields'
import { prefetchWorkspaceAccess } from '@/app/workspace/[workspaceId]/prefetch-access'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
import {
accessRequestKeys,
workspaceFeatureDiscoveryQuery,
-} from '@/hooks/queries/utils/access-request-keys'
+} from '@/ee/access-requests/hooks/access-request-keys'
import { permissionGroupKeys } from '@/hooks/queries/utils/permission-group-keys'
const principal = { kind: 'session', userId: 'viewer', sessionId: 'session' } as const
diff --git a/apps/sim/app/workspace/[workspaceId]/prefetch-access.ts b/apps/sim/app/workspace/[workspaceId]/prefetch-access.ts
index 182426e174a..1b05ba5913a 100644
--- a/apps/sim/app/workspace/[workspaceId]/prefetch-access.ts
+++ b/apps/sim/app/workspace/[workspaceId]/prefetch-access.ts
@@ -11,7 +11,7 @@ import {
ACCESS_REQUESTS_STALE_TIME,
accessRequestKeys,
workspaceFeatureDiscoveryQuery,
-} from '@/hooks/queries/utils/access-request-keys'
+} from '@/ee/access-requests/hooks/access-request-keys'
import {
PERMISSION_GROUPS_STALE_TIME,
permissionGroupKeys,
@@ -46,7 +46,7 @@ export async function prefetchWorkspaceAccess(
queryKey: accessRequestKeys.discovery(query),
queryFn: async () => {
const { discoverAccessRequests } = await import(
- '@/lib/permission-access-requests/application/requests'
+ '@/ee/access-requests/lib/application/requests'
)
return discoverAccessRequestsContract.response.schema.parse(
await discoverAccessRequests.execute({ principal, input: query })
diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.test.tsx b/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.test.tsx
index 04e42904940..aeffeec2629 100644
--- a/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.test.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.test.tsx
@@ -28,7 +28,7 @@ const {
vi.mock('next/navigation', () => ({ notFound: mockNotFound, redirect: mockRedirect }))
vi.mock('@/lib/auth', () => ({ getSession: mockGetSession }))
-vi.mock('@/components/access-requests/permission-access-boundary', () => ({
+vi.mock('@/ee/access-requests/components/permission-access-boundary', () => ({
PermissionAccessBoundary: vi.fn(() => null),
}))
vi.mock('@/lib/settings/application/workspace-section-access', () => ({
diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx b/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx
index 97cf21c2783..df6f6c2d7b9 100644
--- a/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx
@@ -2,7 +2,6 @@ import { Suspense } from 'react'
import { dehydrate, HydrationBoundary } from '@tanstack/react-query'
import type { Metadata } from 'next'
import { notFound, redirect } from 'next/navigation'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { EmptyState } from '@/components/empty-state/empty-state'
import {
getOrganizationSettingsHref,
@@ -13,6 +12,7 @@ import { authorizeWorkspaceSettingsSection } from '@/lib/settings/application/wo
import { getWorkspaceHostContextForViewer } from '@/lib/workspaces/host-context'
import { getQueryClient } from '@/app/_shell/providers/get-query-client'
import { resolveSettingsSection } from '@/app/workspace/[workspaceId]/settings/navigation'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
import { SECTION_PREFETCHERS } from './prefetch'
import { SettingsPage } from './settings'
diff --git a/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx b/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx
index 016de4cb3e4..997bf5af779 100644
--- a/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx
@@ -3,7 +3,6 @@
import { useEffect } from 'react'
import dynamic from 'next/dynamic'
import { usePostHog } from 'posthog-js/react'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import { getSettingsPermissionConfigKey } from '@/components/settings/navigation'
import { useSession } from '@/lib/auth/auth-client'
import { useDeploymentShape } from '@/lib/core/config/deployment-shape'
@@ -15,6 +14,7 @@ import {
getSettingsSectionMeta,
type SettingsSection,
} from '@/app/workspace/[workspaceId]/settings/navigation'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
const Admin = dynamic(() =>
import('@/app/workspace/[workspaceId]/settings/components/admin/admin').then((m) => m.Admin)
diff --git a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/page.tsx b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/page.tsx
index 152bd121970..702187a5ab6 100644
--- a/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/page.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/tables/[tableId]/page.tsx
@@ -1,7 +1,7 @@
import { Suspense } from 'react'
import type { Metadata } from 'next'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import TableLoading from '@/app/workspace/[workspaceId]/tables/[tableId]/loading'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
import { Table } from './table'
export const metadata: Metadata = {
diff --git a/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx b/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx
index 4c68bbdb44c..56257d6dbcc 100644
--- a/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/tables/tables.tsx
@@ -8,7 +8,6 @@ import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { useParams, useRouter } from 'next/navigation'
import { useQueryStates } from 'nuqs'
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
import type { TableDefinition } from '@/lib/table'
import { generateUniqueTableName, MAX_TABLE_BATCH_ITEMS } from '@/lib/table/constants'
import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state'
@@ -80,6 +79,7 @@ import {
tablesSortParams,
tablesUrlKeys,
} from '@/app/workspace/[workspaceId]/tables/search-params'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
import { useCreateFolder, useDeleteFolderMutation, useUpdateFolder } from '@/hooks/queries/folders'
import { usePinItem, usePinnedIds, useUnpinItem } from '@/hooks/queries/pinned-items'
import {
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.test.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.test.tsx
index 9d5ae83298f..71d3b176bd0 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.test.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.test.tsx
@@ -82,10 +82,10 @@ vi.mock('@/hooks/use-permission-config', () => ({
isBlockRequestable: (type: string) => type.startsWith('locked-'),
}),
}))
-vi.mock('@/components/access-requests/permission-access-boundary', () => ({
+vi.mock('@/ee/access-requests/components/permission-access-boundary', () => ({
useWorkspaceAccessRequestFeatures: discovery,
}))
-vi.mock('@/components/access-requests/request-access-action', () => ({
+vi.mock('@/ee/access-requests/components/request-access-action', () => ({
RequestAccessModal: ({ label, onClose }: { label: string; onClose: () => void }) => (
Request {label}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx
index e4323e2c711..09ede00b538 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/toolbar/toolbar.tsx
@@ -24,8 +24,6 @@ import {
import { ChevronDown, Lock, Search } from '@sim/emcn/icons'
import { useParams } from 'next/navigation'
import { usePostHog } from 'posthog-js/react'
-import { useWorkspaceAccessRequestFeatures } from '@/components/access-requests/permission-access-boundary'
-import { RequestAccessModal } from '@/components/access-requests/request-access-action'
import { captureEvent } from '@/lib/posthog/client'
import { getTriggersForSidebar, hasTriggerCapability } from '@/lib/workflows/triggers/trigger-utils'
import {
@@ -41,6 +39,8 @@ import { useCustomBlockOverlayVersion } from '@/blocks/custom/client-overlay'
import { getCustomBlockTile } from '@/blocks/custom/custom-block-icon'
import { getCanonicalBlocksByCategory } from '@/blocks/registry'
import type { BlockConfig } from '@/blocks/types'
+import { useWorkspaceAccessRequestFeatures } from '@/ee/access-requests/components/permission-access-boundary'
+import { RequestAccessModal } from '@/ee/access-requests/components/request-access-action'
import { useOrgBrandConfig } from '@/ee/whitelabeling/components/branding-provider'
import { useCustomBlocks } from '@/hooks/queries/custom-blocks'
import { usePermissionConfig } from '@/hooks/use-permission-config'
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx
index cd6873ce25e..5f894cfc5f3 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx
@@ -27,7 +27,6 @@ import { useQueryClient } from '@tanstack/react-query'
import { useParams, useRouter } from 'next/navigation'
import { usePostHog } from 'posthog-js/react'
import { useShallow } from 'zustand/react/shallow'
-import { RequestAccessModal } from '@/components/access-requests/request-access-action'
import { VariableIcon } from '@/components/icons'
import { ThinkingLoader } from '@/components/ui'
import { requestJson } from '@/lib/api/client/request'
@@ -68,7 +67,8 @@ import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]
import { useWorkflowExecution } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution'
import { getWorkflowLockToggleIds } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils'
import { useDeleteWorkflow, useImportWorkflow } from '@/app/workspace/[workspaceId]/w/hooks'
-import { useDiscoverAccessRequests } from '@/hooks/queries/access-requests'
+import { RequestAccessModal } from '@/ee/access-requests/components/request-access-action'
+import { useDiscoverAccessRequests } from '@/ee/access-requests/hooks/access-requests'
import { useCopilotChatSelection } from '@/hooks/queries/copilot-chat-selection'
import {
type CopilotChatListItem,
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.test.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.test.tsx
index 8b89a41104f..cc1deb58045 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.test.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.test.tsx
@@ -68,7 +68,7 @@ vi.mock('@/hooks/use-permission-config', () => ({
}),
}))
-vi.mock('@/hooks/queries/access-requests', () => ({
+vi.mock('@/ee/access-requests/hooks/access-requests', () => ({
useDiscoverAccessRequests: () => ({ data: { enabled: false, entries: [] }, isPending: false }),
}))
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx
index 0d6017ea30a..85a47af1cf1 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx
@@ -40,7 +40,6 @@ import { Command } from 'cmdk'
import { useParams, useRouter } from 'next/navigation'
import { usePostHog } from 'posthog-js/react'
import { createPortal } from 'react-dom'
-import { useWorkspaceAccessRequestFeatures } from '@/components/access-requests/permission-access-boundary'
import { supportsAtomicBrowserPanelOcclusion } from '@/lib/browser-agent/transport'
import { useDeploymentShape } from '@/lib/core/config/deployment-shape'
import { MothershipHandoffStorage } from '@/lib/core/utils/browser-storage'
@@ -89,6 +88,7 @@ import {
CMDK_SECTION_GAP_CLASS,
} from '@/app/workspace/[workspaceId]/w/components/sidebar/constants'
import { SIDEBAR_SCROLL_EVENT } from '@/app/workspace/[workspaceId]/w/components/sidebar/sidebar'
+import { useWorkspaceAccessRequestFeatures } from '@/ee/access-requests/components/permission-access-boundary'
import { useFolderMap } from '@/hooks/queries/folders'
import { useKnowledgeBasesQuery } from '@/hooks/queries/kb/knowledge'
import { useTablesList } from '@/hooks/queries/tables'
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-sidebar/settings-sidebar.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-sidebar/settings-sidebar.tsx
index bbe633e516a..c9f4f040c84 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-sidebar/settings-sidebar.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/settings-sidebar/settings-sidebar.tsx
@@ -16,7 +16,6 @@ import {
import { ArrowUpRight, Building, ChevronLeft, Lock } from '@sim/emcn/icons'
import { useQueryClient } from '@tanstack/react-query'
import { useParams, usePathname, useRouter } from 'next/navigation'
-import { useWorkspaceAccessRequestFeatures } from '@/components/access-requests/permission-access-boundary'
import {
type DesktopSettingsSurface,
getOrganizationSettingsHref,
@@ -47,6 +46,7 @@ import {
SIDEBAR_RAIL_CHIP_CLASS,
SIDEBAR_SECTION_GAP_CLASS,
} from '@/app/workspace/[workspaceId]/w/components/sidebar/constants'
+import { useWorkspaceAccessRequestFeatures } from '@/ee/access-requests/components/permission-access-boundary'
import { useSSOProviders } from '@/ee/sso/hooks/sso'
import { useForkingAvailable } from '@/ee/workspace-forking/hooks/use-forking-available'
import { useGeneralSettings } from '@/hooks/queries/general-settings'
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx
index 947d94305e5..2f2d5891a9c 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx
@@ -39,7 +39,6 @@ import {
import { createLogger } from '@sim/logger'
import { useParams, usePathname, useRouter } from 'next/navigation'
import { usePostHog } from 'posthog-js/react'
-import { useWorkspaceAccessRequestFeatures } from '@/components/access-requests/permission-access-boundary'
import { useSession } from '@/lib/auth/auth-client'
import { canViewWorkspaceBillingSettings } from '@/lib/billing/workspace-permissions'
import { focusVisibleBrowserOmnibox } from '@/lib/browser-agent/renderer-shortcuts'
@@ -119,6 +118,7 @@ import {
} from '@/app/workspace/[workspaceId]/w/components/sidebar/utils'
import { useImportWorkflow } from '@/app/workspace/[workspaceId]/w/hooks'
import { useCustomBlockOverlayVersion } from '@/blocks/custom/client-overlay'
+import { useWorkspaceAccessRequestFeatures } from '@/ee/access-requests/components/permission-access-boundary'
import { useWorkspaceCredentials } from '@/hooks/queries/credentials'
import { useFolderMap, useFolders } from '@/hooks/queries/folders'
import { type LogFilters, useLogsList } from '@/hooks/queries/logs'
diff --git a/apps/sim/ee/README.md b/apps/sim/ee/README.md
index 6a7ee3c8d52..c84b39518a3 100644
--- a/apps/sim/ee/README.md
+++ b/apps/sim/ee/README.md
@@ -7,6 +7,7 @@ for production use.
- **SSO (Single Sign-On)**: OIDC and SAML authentication integration
- **Access Control**: Permission groups for fine-grained user access management
+- **Access Requests**: Members request restricted features or a higher credit cap; organization admins review and apply them. On for every entitled organization unless it opts out
- **Whitelabeling**: Custom branding and theming for enterprise deployments
- **Directory provisioning (SCIM)**: SCIM 2.0 user and group provisioning from Okta, Microsoft Entra, and other identity providers, with group-to-access mapping
diff --git a/apps/sim/ee/access-control/components/access-control-layout.test.tsx b/apps/sim/ee/access-control/components/access-control-layout.test.tsx
index 80ee57e878e..e47f7ebcbab 100644
--- a/apps/sim/ee/access-control/components/access-control-layout.test.tsx
+++ b/apps/sim/ee/access-control/components/access-control-layout.test.tsx
@@ -11,7 +11,7 @@ vi.mock('next/navigation', () => ({
usePathname: () => '/settings/access-control',
}))
vi.mock('@/ee/access-control/components/group-detail', () => ({ GroupDetail: () => null }))
-vi.mock('@/components/access-requests/access-request-review', () => ({
+vi.mock('@/ee/access-requests/components/access-request-review', () => ({
AccessRequestReview: () => null,
}))
vi.mock('@/ee/access-control/hooks/permission-groups', () => ({
@@ -23,7 +23,7 @@ vi.mock('@/ee/access-control/hooks/permission-groups', () => ({
vi.mock('@/hooks/queries/organization', () => ({
useOrganizationBilling: () => ({ data: undefined, isPending: false }),
}))
-vi.mock('@/hooks/queries/access-requests', () => ({
+vi.mock('@/ee/access-requests/hooks/access-requests', () => ({
ACCESS_REQUEST_PAGE_SIZE: 25,
useOrganizationAccessRequests: mocks.requests,
useAccessRequestSettings: () => ({ data: { allowRequests: true }, isPending: false }),
diff --git a/apps/sim/ee/access-control/components/access-control.test.tsx b/apps/sim/ee/access-control/components/access-control.test.tsx
index bd2718e1684..a3538511c08 100644
--- a/apps/sim/ee/access-control/components/access-control.test.tsx
+++ b/apps/sim/ee/access-control/components/access-control.test.tsx
@@ -32,7 +32,7 @@ vi.mock('nuqs', () => ({
useQueryState: () => [null, vi.fn()],
useQueryStates: () => [{ 'access-view': 'groups' }, vi.fn()],
}))
-vi.mock('@/components/access-requests/organization-access-requests', () => ({
+vi.mock('@/ee/access-requests/components/organization-access-requests', () => ({
OrganizationAccessRequests: () => null,
}))
vi.mock('@/app/workspace/[workspaceId]/settings/components/settings-empty-state', () => ({
diff --git a/apps/sim/ee/access-control/components/access-control.tsx b/apps/sim/ee/access-control/components/access-control.tsx
index 10869e2f3e3..e013167a580 100644
--- a/apps/sim/ee/access-control/components/access-control.tsx
+++ b/apps/sim/ee/access-control/components/access-control.tsx
@@ -18,11 +18,6 @@ import { createLogger } from '@sim/logger'
import { getErrorMessage } from '@sim/utils/errors'
import { useParams } from 'next/navigation'
import { useQueryState, useQueryStates } from 'nuqs'
-import { OrganizationAccessRequests } from '@/components/access-requests/organization-access-requests'
-import {
- accessRequestUrlOptions,
- accessReviewSearchParams,
-} from '@/components/access-requests/search-params'
import { isEnterprise } from '@/lib/billing/plan-helpers'
import { useDeploymentShape } from '@/lib/core/config/deployment-shape'
import {
@@ -54,6 +49,11 @@ import {
usePermissionGroups,
useUserPermissionConfig,
} from '@/ee/access-control/hooks/permission-groups'
+import { OrganizationAccessRequests } from '@/ee/access-requests/components/organization-access-requests'
+import {
+ accessRequestUrlOptions,
+ accessReviewSearchParams,
+} from '@/ee/access-requests/components/search-params'
import { useOrganizationBilling } from '@/hooks/queries/organization'
const logger = createLogger('AccessControl')
diff --git a/apps/sim/lib/permission-access-requests/README.md b/apps/sim/ee/access-requests/README.md
similarity index 91%
rename from apps/sim/lib/permission-access-requests/README.md
rename to apps/sim/ee/access-requests/README.md
index 0f18a206667..7d0b04e90c6 100644
--- a/apps/sim/lib/permission-access-requests/README.md
+++ b/apps/sim/ee/access-requests/README.md
@@ -2,12 +2,11 @@
Members request access from locked features, the block picker, or **My access requests**. Organization owners and administrators review requests in **Access control → Requests**, **Review access requests** in the workspace menu, or through an authenticated email link. The same queue handles increases to an administrator-set member credit cap.
-## Rollout
+## Deployment
1. Apply migration `0349_permission_access_requests.sql` before deploying the application changes.
-2. Enable the global AppConfig `permission-access-requests` flag. Outside AppConfig deployments, set `PERMISSION_ACCESS_REQUESTS_ENABLED=true`.
-3. Each organization starts with **Allow users to request permissions** enabled. An explicit organization opt-out disables creation and approval and restores existing feature hiding. History, cancellation, and decline remain available.
-4. The existing outbox worker delivers notifications. Email links open authenticated review/history; email never applies a change.
+2. Each organization starts with **Allow users to request permissions** enabled. An explicit organization opt-out disables creation and approval and restores existing feature hiding. History, cancellation, and decline remain available.
+3. The existing outbox worker delivers notifications. Email links open authenticated review/history; email never applies a change.
## Policy and lifecycle
diff --git a/apps/sim/components/access-requests/access-request-review.test.tsx b/apps/sim/ee/access-requests/components/access-request-review.test.tsx
similarity index 97%
rename from apps/sim/components/access-requests/access-request-review.test.tsx
rename to apps/sim/ee/access-requests/components/access-request-review.test.tsx
index 02c969b500f..dc7366e0aaa 100644
--- a/apps/sim/components/access-requests/access-request-review.test.tsx
+++ b/apps/sim/ee/access-requests/components/access-request-review.test.tsx
@@ -5,7 +5,7 @@ import { act } from 'react'
import { toast } from '@sim/emcn'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { AccessRequestReview } from '@/components/access-requests/access-request-review'
+import { AccessRequestReview } from '@/ee/access-requests/components/access-request-review'
vi.mock('@sim/emcn', async (importOriginal) => ({
...(await importOriginal()),
@@ -13,7 +13,7 @@ vi.mock('@sim/emcn', async (importOriginal) => ({
}))
const mocks = vi.hoisted(() => ({ preview: vi.fn(), resolve: vi.fn() }))
-vi.mock('@/hooks/queries/access-requests', () => ({
+vi.mock('@/ee/access-requests/hooks/access-requests', () => ({
useAccessRequestPreview: mocks.preview,
useResolveAccessRequest: mocks.resolve,
}))
diff --git a/apps/sim/components/access-requests/access-request-review.tsx b/apps/sim/ee/access-requests/components/access-request-review.tsx
similarity index 96%
rename from apps/sim/components/access-requests/access-request-review.tsx
rename to apps/sim/ee/access-requests/components/access-request-review.tsx
index db68369704f..6772705a1fc 100644
--- a/apps/sim/components/access-requests/access-request-review.tsx
+++ b/apps/sim/ee/access-requests/components/access-request-review.tsx
@@ -11,9 +11,12 @@ import {
ChipModalHeader,
toast,
} from '@sim/emcn'
-import { PolicyChanges } from '@/components/access-requests/policy-changes'
-import { ACCESS_REQUEST_STATUS_LABELS } from '@/components/access-requests/status'
-import { useAccessRequestPreview, useResolveAccessRequest } from '@/hooks/queries/access-requests'
+import { PolicyChanges } from '@/ee/access-requests/components/policy-changes'
+import { ACCESS_REQUEST_STATUS_LABELS } from '@/ee/access-requests/components/status'
+import {
+ useAccessRequestPreview,
+ useResolveAccessRequest,
+} from '@/ee/access-requests/hooks/access-requests'
interface AccessRequestReviewProps {
organizationId: string
diff --git a/apps/sim/components/access-requests/access-requests-loading.tsx b/apps/sim/ee/access-requests/components/access-requests-loading.tsx
similarity index 100%
rename from apps/sim/components/access-requests/access-requests-loading.tsx
rename to apps/sim/ee/access-requests/components/access-requests-loading.tsx
diff --git a/apps/sim/components/access-requests/member-limit-request-action.tsx b/apps/sim/ee/access-requests/components/member-limit-request-action.tsx
similarity index 82%
rename from apps/sim/components/access-requests/member-limit-request-action.tsx
rename to apps/sim/ee/access-requests/components/member-limit-request-action.tsx
index f174e442c38..f02409de2ad 100644
--- a/apps/sim/components/access-requests/member-limit-request-action.tsx
+++ b/apps/sim/ee/access-requests/components/member-limit-request-action.tsx
@@ -1,8 +1,8 @@
'use client'
-import { RequestAccessAction } from '@/components/access-requests/request-access-action'
import type { AccessRequestScope } from '@/lib/api/contracts/access-requests'
-import { useDiscoverAccessRequests } from '@/hooks/queries/access-requests'
+import { RequestAccessAction } from '@/ee/access-requests/components/request-access-action'
+import { useDiscoverAccessRequests } from '@/ee/access-requests/hooks/access-requests'
interface MemberLimitRequestActionProps {
scope: AccessRequestScope
diff --git a/apps/sim/components/access-requests/my-access-request-details.tsx b/apps/sim/ee/access-requests/components/my-access-request-details.tsx
similarity index 94%
rename from apps/sim/components/access-requests/my-access-request-details.tsx
rename to apps/sim/ee/access-requests/components/my-access-request-details.tsx
index 5eb44c1e1fc..12b69995577 100644
--- a/apps/sim/components/access-requests/my-access-request-details.tsx
+++ b/apps/sim/ee/access-requests/components/my-access-request-details.tsx
@@ -11,9 +11,12 @@ import {
ChipTag,
toast,
} from '@sim/emcn'
-import { ACCESS_REQUEST_STATUS_LABELS } from '@/components/access-requests/status'
import type { AccessRequestScope } from '@/lib/api/contracts/access-requests'
-import { useCancelAccessRequest, useMyAccessRequests } from '@/hooks/queries/access-requests'
+import { ACCESS_REQUEST_STATUS_LABELS } from '@/ee/access-requests/components/status'
+import {
+ useCancelAccessRequest,
+ useMyAccessRequests,
+} from '@/ee/access-requests/hooks/access-requests'
interface MyAccessRequestDetailsProps {
scope: AccessRequestScope
diff --git a/apps/sim/components/access-requests/my-access-requests.test.tsx b/apps/sim/ee/access-requests/components/my-access-requests.test.tsx
similarity index 96%
rename from apps/sim/components/access-requests/my-access-requests.test.tsx
rename to apps/sim/ee/access-requests/components/my-access-requests.test.tsx
index 2913b635dd8..b62b94f4232 100644
--- a/apps/sim/components/access-requests/my-access-requests.test.tsx
+++ b/apps/sim/ee/access-requests/components/my-access-requests.test.tsx
@@ -5,7 +5,7 @@ import { act } from 'react'
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { MyAccessRequests } from '@/components/access-requests/my-access-requests'
+import { MyAccessRequests } from '@/ee/access-requests/components/my-access-requests'
const mocks = vi.hoisted(() => ({
mine: vi.fn(),
@@ -13,7 +13,7 @@ const mocks = vi.hoisted(() => ({
cancel: vi.fn(),
url: vi.fn(),
}))
-vi.mock('@/hooks/queries/access-requests', () => ({
+vi.mock('@/ee/access-requests/hooks/access-requests', () => ({
ACCESS_REQUEST_PAGE_SIZE: 25,
useMyAccessRequests: mocks.mine,
useDiscoverAccessRequests: mocks.discovery,
diff --git a/apps/sim/components/access-requests/my-access-requests.tsx b/apps/sim/ee/access-requests/components/my-access-requests.tsx
similarity index 93%
rename from apps/sim/components/access-requests/my-access-requests.tsx
rename to apps/sim/ee/access-requests/components/my-access-requests.tsx
index 3504065a114..fe9a579f934 100644
--- a/apps/sim/components/access-requests/my-access-requests.tsx
+++ b/apps/sim/ee/access-requests/components/my-access-requests.tsx
@@ -3,27 +3,27 @@
import { Chip, ChipInput, ChipLink, ChipSwitch, ChipTag } from '@sim/emcn'
import { Lock, Search } from '@sim/emcn/icons'
import { useQueryStates } from 'nuqs'
-import { MyAccessRequestDetails } from '@/components/access-requests/my-access-request-details'
-import { RequestAccessAction } from '@/components/access-requests/request-access-action'
-import {
- accessRequestSearchParams,
- accessRequestUrlOptions,
-} from '@/components/access-requests/search-params'
-import { ACCESS_REQUEST_STATUS_LABELS } from '@/components/access-requests/status'
import { EmptyState } from '@/components/empty-state/empty-state'
import type { AccessRequestScope } from '@/lib/api/contracts/access-requests'
import { WORKSPACES_PATH } from '@/lib/navigation/paths'
-import { ACCESS_REQUEST_MAX_SEARCH_LENGTH } from '@/lib/permission-access-requests/constants'
import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state'
import {
RESOURCE_LIST_STACK,
SettingsResourceRow,
} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row'
+import { MyAccessRequestDetails } from '@/ee/access-requests/components/my-access-request-details'
+import { RequestAccessAction } from '@/ee/access-requests/components/request-access-action'
+import {
+ accessRequestSearchParams,
+ accessRequestUrlOptions,
+} from '@/ee/access-requests/components/search-params'
+import { ACCESS_REQUEST_STATUS_LABELS } from '@/ee/access-requests/components/status'
import {
ACCESS_REQUEST_PAGE_SIZE,
useDiscoverAccessRequests,
useMyAccessRequests,
-} from '@/hooks/queries/access-requests'
+} from '@/ee/access-requests/hooks/access-requests'
+import { ACCESS_REQUEST_MAX_SEARCH_LENGTH } from '@/ee/access-requests/lib/constants'
import { useDebounce } from '@/hooks/use-debounce'
import { useDebouncedSearchSetter } from '@/hooks/use-debounced-search-setter'
diff --git a/apps/sim/components/access-requests/organization-access-requests.test.tsx b/apps/sim/ee/access-requests/components/organization-access-requests.test.tsx
similarity index 95%
rename from apps/sim/components/access-requests/organization-access-requests.test.tsx
rename to apps/sim/ee/access-requests/components/organization-access-requests.test.tsx
index 216b03924ed..22a170ba1e4 100644
--- a/apps/sim/components/access-requests/organization-access-requests.test.tsx
+++ b/apps/sim/ee/access-requests/components/organization-access-requests.test.tsx
@@ -11,17 +11,17 @@ const mocks = vi.hoisted(() => ({
mutate: vi.fn(),
refetch: vi.fn(),
}))
-vi.mock('@/hooks/queries/access-requests', () => ({
+vi.mock('@/ee/access-requests/hooks/access-requests', () => ({
ACCESS_REQUEST_PAGE_SIZE: 25,
useAccessRequestSettings: mocks.settings,
useOrganizationAccessRequests: mocks.requests,
useUpdateAccessRequestSettings: mocks.update,
}))
-vi.mock('@/components/access-requests/access-request-review', () => ({
+vi.mock('@/ee/access-requests/components/access-request-review', () => ({
AccessRequestReview: () => null,
}))
-import { OrganizationAccessRequests } from '@/components/access-requests/organization-access-requests'
+import { OrganizationAccessRequests } from '@/ee/access-requests/components/organization-access-requests'
describe('organization access request settings', () => {
let container: HTMLDivElement
diff --git a/apps/sim/components/access-requests/organization-access-requests.tsx b/apps/sim/ee/access-requests/components/organization-access-requests.tsx
similarity index 95%
rename from apps/sim/components/access-requests/organization-access-requests.tsx
rename to apps/sim/ee/access-requests/components/organization-access-requests.tsx
index 08bb9d4eee8..f31ddb33008 100644
--- a/apps/sim/components/access-requests/organization-access-requests.tsx
+++ b/apps/sim/ee/access-requests/components/organization-access-requests.tsx
@@ -3,13 +3,6 @@
import { Chip, ChipDropdown, ChipInput, ChipSwitch, ChipTag, toast } from '@sim/emcn'
import { Search } from '@sim/emcn/icons'
import { useQueryStates } from 'nuqs'
-import { AccessRequestReview } from '@/components/access-requests/access-request-review'
-import {
- accessRequestUrlOptions,
- accessReviewSearchParams,
-} from '@/components/access-requests/search-params'
-import { ACCESS_REQUEST_STATUS_LABELS } from '@/components/access-requests/status'
-import { ACCESS_REQUEST_MAX_SEARCH_LENGTH } from '@/lib/permission-access-requests/constants'
import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state'
import {
SettingsEmptyState,
@@ -21,12 +14,19 @@ import {
SettingsResourceRow,
} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row'
import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section'
+import { AccessRequestReview } from '@/ee/access-requests/components/access-request-review'
+import {
+ accessRequestUrlOptions,
+ accessReviewSearchParams,
+} from '@/ee/access-requests/components/search-params'
+import { ACCESS_REQUEST_STATUS_LABELS } from '@/ee/access-requests/components/status'
import {
ACCESS_REQUEST_PAGE_SIZE,
useAccessRequestSettings,
useOrganizationAccessRequests,
useUpdateAccessRequestSettings,
-} from '@/hooks/queries/access-requests'
+} from '@/ee/access-requests/hooks/access-requests'
+import { ACCESS_REQUEST_MAX_SEARCH_LENGTH } from '@/ee/access-requests/lib/constants'
import { useDebounce } from '@/hooks/use-debounce'
import { useDebouncedSearchSetter } from '@/hooks/use-debounced-search-setter'
diff --git a/apps/sim/components/access-requests/permission-access-boundary.test.tsx b/apps/sim/ee/access-requests/components/permission-access-boundary.test.tsx
similarity index 95%
rename from apps/sim/components/access-requests/permission-access-boundary.test.tsx
rename to apps/sim/ee/access-requests/components/permission-access-boundary.test.tsx
index 6dc658227b3..a48b07d88a6 100644
--- a/apps/sim/components/access-requests/permission-access-boundary.test.tsx
+++ b/apps/sim/ee/access-requests/components/permission-access-boundary.test.tsx
@@ -34,12 +34,14 @@ vi.mock('@sim/emcn/icons', () => ({
BookOpen: () => null,
}))
vi.mock('@/ee/access-control/hooks/permission-groups', () => ({ useUserPermissionConfig: policy }))
-vi.mock('@/hooks/queries/access-requests', () => ({ useDiscoverAccessRequests: discovery }))
-vi.mock('@/components/access-requests/request-access-action', () => ({
+vi.mock('@/ee/access-requests/hooks/access-requests', () => ({
+ useDiscoverAccessRequests: discovery,
+}))
+vi.mock('@/ee/access-requests/components/request-access-action', () => ({
RequestAccessAction: () => ,
}))
-import { PermissionAccessBoundary } from '@/components/access-requests/permission-access-boundary'
+import { PermissionAccessBoundary } from '@/ee/access-requests/components/permission-access-boundary'
describe('PermissionAccessBoundary', () => {
let container: HTMLDivElement
diff --git a/apps/sim/components/access-requests/permission-access-boundary.tsx b/apps/sim/ee/access-requests/components/permission-access-boundary.tsx
similarity index 94%
rename from apps/sim/components/access-requests/permission-access-boundary.tsx
rename to apps/sim/ee/access-requests/components/permission-access-boundary.tsx
index bc111f3e694..77d0f78487b 100644
--- a/apps/sim/components/access-requests/permission-access-boundary.tsx
+++ b/apps/sim/ee/access-requests/components/permission-access-boundary.tsx
@@ -3,15 +3,15 @@
import type { ReactNode } from 'react'
import { Chip } from '@sim/emcn'
import { useParams, useRouter } from 'next/navigation'
-import { RequestAccessAction } from '@/components/access-requests/request-access-action'
import { EmptyState } from '@/components/empty-state/empty-state'
import type { BooleanPermissionGroupConfigKey } from '@/lib/permission-groups/features'
import { FilesEmptyState } from '@/app/workspace/[workspaceId]/components/resource/components/resource-empty-state/files-empty-state'
import { KnowledgeEmptyState } from '@/app/workspace/[workspaceId]/components/resource/components/resource-empty-state/knowledge-empty-state'
import { TablesEmptyState } from '@/app/workspace/[workspaceId]/components/resource/components/resource-empty-state/tables-empty-state'
import { useUserPermissionConfig } from '@/ee/access-control/hooks/permission-groups'
-import { useDiscoverAccessRequests } from '@/hooks/queries/access-requests'
-import { workspaceFeatureDiscoveryQuery } from '@/hooks/queries/utils/access-request-keys'
+import { RequestAccessAction } from '@/ee/access-requests/components/request-access-action'
+import { workspaceFeatureDiscoveryQuery } from '@/ee/access-requests/hooks/access-request-keys'
+import { useDiscoverAccessRequests } from '@/ee/access-requests/hooks/access-requests'
/** Safe feature metadata shared by navigation and access-required pages. */
export function useWorkspaceAccessRequestFeatures() {
diff --git a/apps/sim/components/access-requests/policy-changes.test.ts b/apps/sim/ee/access-requests/components/policy-changes.test.ts
similarity index 99%
rename from apps/sim/components/access-requests/policy-changes.test.ts
rename to apps/sim/ee/access-requests/components/policy-changes.test.ts
index ace9e0ae6c6..173bbff5f98 100644
--- a/apps/sim/components/access-requests/policy-changes.test.ts
+++ b/apps/sim/ee/access-requests/components/policy-changes.test.ts
@@ -5,7 +5,7 @@ import { describe, expect, it } from 'vitest'
import {
describePolicyChange,
describePolicyValue,
-} from '@/components/access-requests/policy-changes'
+} from '@/ee/access-requests/components/policy-changes'
const target = { kind: 'integration', id: 'slack_v2' } as const
diff --git a/apps/sim/components/access-requests/policy-changes.tsx b/apps/sim/ee/access-requests/components/policy-changes.tsx
similarity index 100%
rename from apps/sim/components/access-requests/policy-changes.tsx
rename to apps/sim/ee/access-requests/components/policy-changes.tsx
diff --git a/apps/sim/components/access-requests/request-access-action.test.tsx b/apps/sim/ee/access-requests/components/request-access-action.test.tsx
similarity index 98%
rename from apps/sim/components/access-requests/request-access-action.test.tsx
rename to apps/sim/ee/access-requests/components/request-access-action.test.tsx
index 8a4263d68ff..7a13b40ac72 100644
--- a/apps/sim/components/access-requests/request-access-action.test.tsx
+++ b/apps/sim/ee/access-requests/components/request-access-action.test.tsx
@@ -4,8 +4,8 @@
import { act } from 'react'
import { createRoot, type Root } from 'react-dom/client'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
-import { RequestAccessAction } from '@/components/access-requests/request-access-action'
import type { AccessRequestTarget } from '@/lib/api/contracts/access-requests'
+import { RequestAccessAction } from '@/ee/access-requests/components/request-access-action'
const mocks = vi.hoisted(() => ({
discovery: vi.fn(),
@@ -17,7 +17,7 @@ vi.mock('next/navigation', () => ({
useRouter: () => ({ push: mocks.push }),
usePathname: () => '/workspace/workspace',
}))
-vi.mock('@/hooks/queries/access-requests', () => ({
+vi.mock('@/ee/access-requests/hooks/access-requests', () => ({
useCreateAccessRequest: () => ({ mutate: mocks.create, isPending: false, error: null }),
useDiscoverAccessRequests: mocks.discovery,
}))
diff --git a/apps/sim/components/access-requests/request-access-action.tsx b/apps/sim/ee/access-requests/components/request-access-action.tsx
similarity index 97%
rename from apps/sim/components/access-requests/request-access-action.tsx
rename to apps/sim/ee/access-requests/components/request-access-action.tsx
index 34e5703d77f..49f5641ce3d 100644
--- a/apps/sim/components/access-requests/request-access-action.tsx
+++ b/apps/sim/ee/access-requests/components/request-access-action.tsx
@@ -17,8 +17,11 @@ import {
import { Lock } from '@sim/emcn/icons'
import { useRouter } from 'next/navigation'
import type { AccessRequestScope, AccessRequestTarget } from '@/lib/api/contracts/access-requests'
-import { getAccessRequestTargetKey } from '@/lib/permission-groups/access-requests/targets'
-import { useCreateAccessRequest, useDiscoverAccessRequests } from '@/hooks/queries/access-requests'
+import {
+ useCreateAccessRequest,
+ useDiscoverAccessRequests,
+} from '@/ee/access-requests/hooks/access-requests'
+import { getAccessRequestTargetKey } from '@/ee/access-requests/lib/targets'
interface RequestAccessActionProps {
scope: AccessRequestScope
diff --git a/apps/sim/components/access-requests/search-params.test.ts b/apps/sim/ee/access-requests/components/search-params.test.ts
similarity index 95%
rename from apps/sim/components/access-requests/search-params.test.ts
rename to apps/sim/ee/access-requests/components/search-params.test.ts
index 9a6f1a531b0..98846339a08 100644
--- a/apps/sim/components/access-requests/search-params.test.ts
+++ b/apps/sim/ee/access-requests/components/search-params.test.ts
@@ -5,7 +5,7 @@ import { describe, expect, it } from 'vitest'
import {
accessRequestSearchParams,
accessReviewSearchParams,
-} from '@/components/access-requests/search-params'
+} from '@/ee/access-requests/components/search-params'
describe('access request URL bounds', () => {
it.each(['-1', '1.5', '40001', '1e3', '999999999999999999999'])(
diff --git a/apps/sim/components/access-requests/search-params.ts b/apps/sim/ee/access-requests/components/search-params.ts
similarity index 97%
rename from apps/sim/components/access-requests/search-params.ts
rename to apps/sim/ee/access-requests/components/search-params.ts
index 639adf68736..efe8d9cdb99 100644
--- a/apps/sim/components/access-requests/search-params.ts
+++ b/apps/sim/ee/access-requests/components/search-params.ts
@@ -4,7 +4,7 @@ import {
ACCESS_REQUEST_MAX_ID_LENGTH,
ACCESS_REQUEST_MAX_OFFSET,
ACCESS_REQUEST_MAX_SEARCH_LENGTH,
-} from '@/lib/permission-access-requests/constants'
+} from '@/ee/access-requests/lib/constants'
const accessRequestPageParser = createParser({
parse(value) {
diff --git a/apps/sim/components/access-requests/status.ts b/apps/sim/ee/access-requests/components/status.ts
similarity index 100%
rename from apps/sim/components/access-requests/status.ts
rename to apps/sim/ee/access-requests/components/status.ts
diff --git a/apps/sim/hooks/queries/utils/access-request-keys.ts b/apps/sim/ee/access-requests/hooks/access-request-keys.ts
similarity index 100%
rename from apps/sim/hooks/queries/utils/access-request-keys.ts
rename to apps/sim/ee/access-requests/hooks/access-request-keys.ts
diff --git a/apps/sim/hooks/queries/access-requests.test.tsx b/apps/sim/ee/access-requests/hooks/access-requests.test.tsx
similarity index 98%
rename from apps/sim/hooks/queries/access-requests.test.tsx
rename to apps/sim/ee/access-requests/hooks/access-requests.test.tsx
index 21d97bf12b7..9ce34d47fc1 100644
--- a/apps/sim/hooks/queries/access-requests.test.tsx
+++ b/apps/sim/ee/access-requests/hooks/access-requests.test.tsx
@@ -14,12 +14,12 @@ import {
listMyAccessRequestsContract,
resolveAccessRequestContract,
} from '@/lib/api/contracts/access-requests'
+import { accessRequestKeys } from '@/ee/access-requests/hooks/access-request-keys'
import {
useDiscoverAccessRequests,
useMyAccessRequests,
useResolveAccessRequest,
-} from '@/hooks/queries/access-requests'
-import { accessRequestKeys } from '@/hooks/queries/utils/access-request-keys'
+} from '@/ee/access-requests/hooks/access-requests'
import { organizationKeys } from '@/hooks/queries/utils/organization-keys'
import { workspaceUsageKeys } from '@/hooks/queries/utils/workspace-usage-keys'
diff --git a/apps/sim/hooks/queries/access-requests.ts b/apps/sim/ee/access-requests/hooks/access-requests.ts
similarity index 98%
rename from apps/sim/hooks/queries/access-requests.ts
rename to apps/sim/ee/access-requests/hooks/access-requests.ts
index dfa5d75d6d0..9b1d31d5c6d 100644
--- a/apps/sim/hooks/queries/access-requests.ts
+++ b/apps/sim/ee/access-requests/hooks/access-requests.ts
@@ -22,11 +22,11 @@ import type {
WorkspaceCreditAvailability,
WorkspaceUsageGate,
} from '@/lib/api/contracts/workspaces'
-import { ACCESS_REQUEST_LIST_PAGE_SIZE } from '@/lib/permission-access-requests/constants'
import {
ACCESS_REQUESTS_STALE_TIME,
accessRequestKeys,
-} from '@/hooks/queries/utils/access-request-keys'
+} from '@/ee/access-requests/hooks/access-request-keys'
+import { ACCESS_REQUEST_LIST_PAGE_SIZE } from '@/ee/access-requests/lib/constants'
import { invalidateWorkspaceUsage } from '@/hooks/queries/utils/invalidate-usage'
import { organizationKeys } from '@/hooks/queries/utils/organization-keys'
import { permissionGroupKeys } from '@/hooks/queries/utils/permission-group-keys'
diff --git a/apps/sim/lib/permission-access-requests/application/authorization.test.ts b/apps/sim/ee/access-requests/lib/application/authorization.test.ts
similarity index 98%
rename from apps/sim/lib/permission-access-requests/application/authorization.test.ts
rename to apps/sim/ee/access-requests/lib/application/authorization.test.ts
index 679a19206fb..bb0e652f8e8 100644
--- a/apps/sim/lib/permission-access-requests/application/authorization.test.ts
+++ b/apps/sim/ee/access-requests/lib/application/authorization.test.ts
@@ -18,8 +18,8 @@ import type { DbOrTx } from '@/lib/db/types'
import {
authorizeAccessRequestScope,
loadAccessRequestMembership,
-} from '@/lib/permission-access-requests/application/authorization'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
+} from '@/ee/access-requests/lib/application/authorization'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
const principal: SessionPrincipal = { kind: 'session', userId: 'person', sessionId: 'session' }
const workspaceScope = { kind: 'workspace' as const, workspaceId: 'workspace' }
diff --git a/apps/sim/lib/permission-access-requests/application/authorization.ts b/apps/sim/ee/access-requests/lib/application/authorization.ts
similarity index 96%
rename from apps/sim/lib/permission-access-requests/application/authorization.ts
rename to apps/sim/ee/access-requests/lib/application/authorization.ts
index 0dac5ff2e7c..6e613b6c737 100644
--- a/apps/sim/lib/permission-access-requests/application/authorization.ts
+++ b/apps/sim/ee/access-requests/lib/application/authorization.ts
@@ -15,8 +15,8 @@ import {
} from '@/lib/core/application/workspace-authorization'
import { OrchestrationError } from '@/lib/core/orchestration/types'
import type { DbOrTx } from '@/lib/db/types'
-import type { AccessRequestOperation } from '@/lib/permission-access-requests/application/operations'
-import type { AccessRequestScope } from '@/lib/permission-groups/access-requests/targets'
+import type { AccessRequestOperation } from '@/ee/access-requests/lib/application/operations'
+import type { AccessRequestScope } from '@/ee/access-requests/lib/targets'
export interface AccessRequestContext {
organizationId: string | null
diff --git a/apps/sim/lib/permission-access-requests/application/authorized-use-case.test.ts b/apps/sim/ee/access-requests/lib/application/authorized-use-case.test.ts
similarity index 96%
rename from apps/sim/lib/permission-access-requests/application/authorized-use-case.test.ts
rename to apps/sim/ee/access-requests/lib/application/authorized-use-case.test.ts
index 607dc7a6963..652f072253b 100644
--- a/apps/sim/lib/permission-access-requests/application/authorized-use-case.test.ts
+++ b/apps/sim/ee/access-requests/lib/application/authorized-use-case.test.ts
@@ -9,7 +9,7 @@ const mocks = vi.hoisted(() => ({
audit: vi.fn(),
outbound: vi.fn(),
}))
-vi.mock('@/lib/permission-access-requests/application/authorization', () => ({
+vi.mock('@/ee/access-requests/lib/application/authorization', () => ({
authorizeAccessRequestScope: mocks.authorize,
}))
vi.mock('@/lib/billing/organizations/membership', () => ({
@@ -25,8 +25,8 @@ vi.mock('@/lib/core/network/context.server', () => ({
import type { AccessRequestScope } from '@/lib/api/contracts/access-requests'
import { OrchestrationError } from '@/lib/core/orchestration/types'
import type { DbOrTx } from '@/lib/db/types'
-import { defineAuthorizedAccessRequestUseCase } from '@/lib/permission-access-requests/application/authorized-use-case'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
+import { defineAuthorizedAccessRequestUseCase } from '@/ee/access-requests/lib/application/authorized-use-case'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
const principal: SessionPrincipal = { kind: 'session', userId: 'requester', sessionId: 'session' }
const scope: AccessRequestScope = { kind: 'workspace', workspaceId: 'workspace' }
diff --git a/apps/sim/lib/permission-access-requests/application/authorized-use-case.ts b/apps/sim/ee/access-requests/lib/application/authorized-use-case.ts
similarity index 94%
rename from apps/sim/lib/permission-access-requests/application/authorized-use-case.ts
rename to apps/sim/ee/access-requests/lib/application/authorized-use-case.ts
index 7eea4a76977..3672ee15f84 100644
--- a/apps/sim/lib/permission-access-requests/application/authorized-use-case.ts
+++ b/apps/sim/ee/access-requests/lib/application/authorized-use-case.ts
@@ -12,9 +12,9 @@ import type { DbOrTx } from '@/lib/db/types'
import {
type AccessRequestContext,
authorizeAccessRequestScope,
-} from '@/lib/permission-access-requests/application/authorization'
-import type { AccessRequestOperation } from '@/lib/permission-access-requests/application/operations'
-import type { AccessRequestScope } from '@/lib/permission-groups/access-requests/targets'
+} from '@/ee/access-requests/lib/application/authorization'
+import type { AccessRequestOperation } from '@/ee/access-requests/lib/application/operations'
+import type { AccessRequestScope } from '@/ee/access-requests/lib/targets'
interface AccessRequestPreparationArgs {
principal: SessionPrincipal
diff --git a/apps/sim/lib/permission-access-requests/application/operations.ts b/apps/sim/ee/access-requests/lib/application/operations.ts
similarity index 100%
rename from apps/sim/lib/permission-access-requests/application/operations.ts
rename to apps/sim/ee/access-requests/lib/application/operations.ts
diff --git a/apps/sim/lib/permission-access-requests/application/prepare.ts b/apps/sim/ee/access-requests/lib/application/prepare.ts
similarity index 67%
rename from apps/sim/lib/permission-access-requests/application/prepare.ts
rename to apps/sim/ee/access-requests/lib/application/prepare.ts
index a05269b1f9d..11568b99267 100644
--- a/apps/sim/lib/permission-access-requests/application/prepare.ts
+++ b/apps/sim/ee/access-requests/lib/application/prepare.ts
@@ -1,10 +1,9 @@
import { isOrganizationOnEnterprisePlan } from '@/lib/billing/core/subscription'
import { isAccessControlEnabled, isHosted } from '@/lib/core/config/env-flags'
-import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
import { OrchestrationError } from '@/lib/core/orchestration/types'
-import type { AccessRequestContext } from '@/lib/permission-access-requests/application/authorization'
-import { loadAccessRequestCatalog } from '@/lib/permission-access-requests/catalog'
-import type { AccessRequestTarget } from '@/lib/permission-groups/access-requests/targets'
+import type { AccessRequestContext } from '@/ee/access-requests/lib/application/authorization'
+import { loadAccessRequestCatalog } from '@/ee/access-requests/lib/catalog'
+import type { AccessRequestTarget } from '@/ee/access-requests/lib/targets'
/** Resolve deployment metadata before opening a transaction or taking policy locks. */
export async function prepareAccessRequestPolicy(
@@ -17,7 +16,7 @@ export async function prepareAccessRequestPolicy(
'forbidden',
'Access requests require an organization-owned workspace'
)
- const [catalog, entitled, globalEnabled] = await Promise.all([
+ const [catalog, entitled] = await Promise.all([
loadAccessRequestCatalog(
{
organizationId: context.organizationId,
@@ -29,9 +28,8 @@ export async function prepareAccessRequestPolicy(
isHosted
? isOrganizationOnEnterprisePlan(context.organizationId)
: Promise.resolve(isAccessControlEnabled),
- isFeatureEnabled('permission-access-requests'),
])
- return { catalog, entitled, globalEnabled }
+ return { catalog, entitled }
}
export type PreparedAccessRequestPolicy = Awaited>
diff --git a/apps/sim/lib/permission-access-requests/application/requests.test.ts b/apps/sim/ee/access-requests/lib/application/requests.test.ts
similarity index 96%
rename from apps/sim/lib/permission-access-requests/application/requests.test.ts
rename to apps/sim/ee/access-requests/lib/application/requests.test.ts
index 616c518ca57..c3e20698881 100644
--- a/apps/sim/lib/permission-access-requests/application/requests.test.ts
+++ b/apps/sim/ee/access-requests/lib/application/requests.test.ts
@@ -11,9 +11,9 @@ import {
import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { AccessRequestRecord, AccessRequestTarget } from '@/lib/api/contracts/access-requests'
-import type { StoredAccessRequest } from '@/lib/permission-access-requests/repository'
-import { createAccessRequestCatalog } from '@/lib/permission-groups/access-requests/targets'
import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields'
+import type { StoredAccessRequest } from '@/ee/access-requests/lib/repository'
+import { createAccessRequestCatalog } from '@/ee/access-requests/lib/targets'
const mocks = vi.hoisted(() => ({
authorize: vi.fn(),
@@ -23,7 +23,6 @@ const mocks = vi.hoisted(() => ({
audit: vi.fn(),
outbox: vi.fn(),
enabled: vi.fn(),
- featureEnabled: vi.fn(),
enterprise: vi.fn(),
catalog: vi.fn(),
targets: vi.fn(),
@@ -34,7 +33,7 @@ const mocks = vi.hoisted(() => ({
list: vi.fn(),
}))
-vi.mock('@/lib/permission-access-requests/application/authorization', () => ({
+vi.mock('@/ee/access-requests/lib/application/authorization', () => ({
authorizeAccessRequestScope: mocks.authorize,
loadAccessRequestMembership: mocks.membership,
}))
@@ -46,16 +45,15 @@ vi.mock('@/lib/core/application/authorized-workspace-use-case', () => ({
}))
vi.mock('@/lib/core/outbox/service', () => ({ enqueueOutboxEvent: mocks.outbox }))
vi.mock('@/lib/permission-groups/locks', () => ({ acquirePermissionGroupOrgLock: mocks.groupLock }))
-vi.mock('@/lib/permission-access-requests/settings', () => ({
+vi.mock('@/ee/access-requests/lib/settings', () => ({
isAccessRequestEnabled: mocks.enabled,
readAccessRequestSettings: vi.fn(),
}))
-vi.mock('@/lib/core/config/feature-flags', () => ({ isFeatureEnabled: mocks.featureEnabled }))
vi.mock('@/lib/core/config/env-flags', () => ({ isHosted: true, isAccessControlEnabled: true }))
vi.mock('@/lib/billing/core/subscription', () => ({
isOrganizationOnEnterprisePlan: mocks.enterprise,
}))
-vi.mock('@/lib/permission-access-requests/catalog', () => ({
+vi.mock('@/ee/access-requests/lib/catalog', () => ({
loadAccessRequestCatalog: mocks.catalog,
listAccessRequestTargets: mocks.targets,
getAccessRequestDeploymentUnavailableReason: mocks.deploymentReason,
@@ -64,7 +62,7 @@ vi.mock('@/lib/permission-groups/resolve.server', () => ({
resolveWorkspaceGroup: mocks.group,
resolveDefaultGroup: mocks.group,
}))
-vi.mock('@/lib/permission-access-requests/repository', () => ({
+vi.mock('@/ee/access-requests/lib/repository', () => ({
presentAccessRequest: mocks.present,
loadStoredAccessRequest: mocks.stored,
listAccessRequestRecords: mocks.list,
@@ -75,11 +73,11 @@ import {
createAccessRequest,
discoverAccessRequests,
listMyAccessRequests,
-} from '@/lib/permission-access-requests/application/requests'
+} from '@/ee/access-requests/lib/application/requests'
import {
PERMISSION_ACCESS_REQUEST_CREATED_EVENT,
PERMISSION_ACCESS_REQUEST_DECIDED_EVENT,
-} from '@/lib/permission-access-requests/notification-events'
+} from '@/ee/access-requests/lib/notification-events'
const principal = { kind: 'session', userId: 'requester', sessionId: 'session' } as const
const scope = { kind: 'workspace', workspaceId: 'workspace' } as const
@@ -152,7 +150,6 @@ beforeEach(() => {
mocks.authorize.mockResolvedValue(context)
mocks.membership.mockResolvedValue(null)
mocks.enabled.mockResolvedValue(true)
- mocks.featureEnabled.mockResolvedValue(true)
mocks.enterprise.mockResolvedValue(true)
mocks.catalog.mockResolvedValue(catalog)
mocks.deploymentReason.mockReturnValue(null)
diff --git a/apps/sim/lib/permission-access-requests/application/requests.ts b/apps/sim/ee/access-requests/lib/application/requests.ts
similarity index 94%
rename from apps/sim/lib/permission-access-requests/application/requests.ts
rename to apps/sim/ee/access-requests/lib/application/requests.ts
index 0f5ed0715ed..e3bf1be02d5 100644
--- a/apps/sim/lib/permission-access-requests/application/requests.ts
+++ b/apps/sim/ee/access-requests/lib/application/requests.ts
@@ -9,37 +9,44 @@ import { and, count, eq, gte, isNull, or } from 'drizzle-orm'
import { OrchestrationError } from '@/lib/core/orchestration/types'
import { enqueueOutboxEvent } from '@/lib/core/outbox/service'
import type { DbOrTx } from '@/lib/db/types'
-import type { AccessRequestContext } from '@/lib/permission-access-requests/application/authorization'
-import { loadAccessRequestMembership } from '@/lib/permission-access-requests/application/authorization'
-import { defineAuthorizedAccessRequestUseCase } from '@/lib/permission-access-requests/application/authorized-use-case'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
-import { prepareAccessRequestPolicy } from '@/lib/permission-access-requests/application/prepare'
+import { acquirePermissionGroupOrgLock } from '@/lib/permission-groups/locks'
+import type { AccessRequestContext } from '@/ee/access-requests/lib/application/authorization'
+import { loadAccessRequestMembership } from '@/ee/access-requests/lib/application/authorization'
+import { defineAuthorizedAccessRequestUseCase } from '@/ee/access-requests/lib/application/authorized-use-case'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
+import { prepareAccessRequestPolicy } from '@/ee/access-requests/lib/application/prepare'
import {
listAccessRequestTargets,
loadAccessRequestCatalog,
-} from '@/lib/permission-access-requests/catalog'
+} from '@/ee/access-requests/lib/catalog'
import {
ACCESS_REQUEST_MAX_DAILY_SUBMISSIONS,
ACCESS_REQUEST_MAX_PENDING,
ACCESS_REQUEST_SUBMISSION_WINDOW_MS,
-} from '@/lib/permission-access-requests/constants'
+} from '@/ee/access-requests/lib/constants'
import {
PERMISSION_ACCESS_REQUEST_CREATED_EVENT,
PERMISSION_ACCESS_REQUEST_DECIDED_EVENT,
-} from '@/lib/permission-access-requests/notification-events'
+} from '@/ee/access-requests/lib/notification-events'
import {
evaluateAccessRequestTarget,
loadAccessRequestPolicy,
-} from '@/lib/permission-access-requests/policy'
+} from '@/ee/access-requests/lib/policy'
import {
listAccessRequestRecords,
loadStoredAccessRequest,
presentAccessRequest,
-} from '@/lib/permission-access-requests/repository'
+} from '@/ee/access-requests/lib/repository'
import {
isAccessRequestEnabled,
readAccessRequestSettings,
-} from '@/lib/permission-access-requests/settings'
+} from '@/ee/access-requests/lib/settings'
+import type { AccessRequestScope } from '@/ee/access-requests/lib/targets'
+import {
+ describeAccessRequestTarget,
+ getAccessRequestTargetKey,
+ validateAccessRequestTarget,
+} from '@/ee/access-requests/lib/targets'
import type {
AccessRequestDiscovery,
AccessRequestRecord,
@@ -47,14 +54,7 @@ import type {
AccessRequestStatus,
CreateAccessRequestInput,
DiscoverAccessRequestsInput,
-} from '@/lib/permission-access-requests/types'
-import type { AccessRequestScope } from '@/lib/permission-groups/access-requests/targets'
-import {
- describeAccessRequestTarget,
- getAccessRequestTargetKey,
- validateAccessRequestTarget,
-} from '@/lib/permission-groups/access-requests/targets'
-import { acquirePermissionGroupOrgLock } from '@/lib/permission-groups/locks'
+} from '@/ee/access-requests/lib/types'
function requireOrganization(organizationId: string | null): string {
if (!organizationId)
@@ -229,7 +229,7 @@ export const createAccessRequest = defineAuthorizedAccessRequestUseCase({
prepared,
}): Promise {
const organizationId = requireOrganization(context.organizationId)
- if (!(await isAccessRequestEnabled(organizationId, executor, prepared.globalEnabled)))
+ if (!(await isAccessRequestEnabled(organizationId, executor)))
throw new OrchestrationError(
'forbidden',
'Access requests are turned off for this organization'
diff --git a/apps/sim/lib/permission-access-requests/application/review.test.ts b/apps/sim/ee/access-requests/lib/application/review.test.ts
similarity index 95%
rename from apps/sim/lib/permission-access-requests/application/review.test.ts
rename to apps/sim/ee/access-requests/lib/application/review.test.ts
index cc111932b7f..f4abf9fe9a6 100644
--- a/apps/sim/lib/permission-access-requests/application/review.test.ts
+++ b/apps/sim/ee/access-requests/lib/application/review.test.ts
@@ -12,9 +12,9 @@ import {
import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { AccessRequestRecord, AccessRequestTarget } from '@/lib/api/contracts/access-requests'
-import type { StoredAccessRequest } from '@/lib/permission-access-requests/repository'
-import { createAccessRequestCatalog } from '@/lib/permission-groups/access-requests/targets'
import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields'
+import type { StoredAccessRequest } from '@/ee/access-requests/lib/repository'
+import { createAccessRequestCatalog } from '@/ee/access-requests/lib/targets'
const mocks = vi.hoisted(() => ({
authorize: vi.fn(),
@@ -24,7 +24,6 @@ const mocks = vi.hoisted(() => ({
audit: vi.fn(),
outbox: vi.fn(),
enabled: vi.fn(),
- featureEnabled: vi.fn(),
enterprise: vi.fn(),
catalog: vi.fn(),
deploymentReason: vi.fn(),
@@ -35,7 +34,7 @@ const mocks = vi.hoisted(() => ({
setLimit: vi.fn(),
}))
-vi.mock('@/lib/permission-access-requests/application/authorization', () => ({
+vi.mock('@/ee/access-requests/lib/application/authorization', () => ({
authorizeAccessRequestScope: mocks.authorize,
loadAccessRequestMembership: mocks.membership,
}))
@@ -47,15 +46,14 @@ vi.mock('@/lib/core/application/authorized-workspace-use-case', () => ({
}))
vi.mock('@/lib/core/outbox/service', () => ({ enqueueOutboxEvent: mocks.outbox }))
vi.mock('@/lib/permission-groups/locks', () => ({ acquirePermissionGroupOrgLock: mocks.groupLock }))
-vi.mock('@/lib/permission-access-requests/settings', () => ({
+vi.mock('@/ee/access-requests/lib/settings', () => ({
isAccessRequestEnabled: mocks.enabled,
}))
-vi.mock('@/lib/core/config/feature-flags', () => ({ isFeatureEnabled: mocks.featureEnabled }))
vi.mock('@/lib/core/config/env-flags', () => ({ isHosted: true, isAccessControlEnabled: true }))
vi.mock('@/lib/billing/core/subscription', () => ({
isOrganizationOnEnterprisePlan: mocks.enterprise,
}))
-vi.mock('@/lib/permission-access-requests/catalog', () => ({
+vi.mock('@/ee/access-requests/lib/catalog', () => ({
loadAccessRequestCatalog: mocks.catalog,
getAccessRequestDeploymentUnavailableReason: mocks.deploymentReason,
}))
@@ -63,10 +61,10 @@ vi.mock('@/lib/permission-groups/resolve.server', () => ({
resolveWorkspaceGroup: mocks.group,
resolveDefaultGroup: mocks.group,
}))
-vi.mock('@/lib/permission-access-requests/impact', () => ({
+vi.mock('@/ee/access-requests/lib/impact', () => ({
loadAccessRequestGroupImpact: mocks.impact,
}))
-vi.mock('@/lib/permission-access-requests/repository', () => ({
+vi.mock('@/ee/access-requests/lib/repository', () => ({
presentAccessRequest: mocks.present,
loadStoredAccessRequest: mocks.stored,
}))
@@ -77,8 +75,8 @@ vi.mock('@/lib/billing/organizations/member-limits', () => ({
import {
previewAccessRequest,
resolveAccessRequest,
-} from '@/lib/permission-access-requests/application/review'
-import { PERMISSION_ACCESS_REQUEST_DECIDED_EVENT } from '@/lib/permission-access-requests/notification-events'
+} from '@/ee/access-requests/lib/application/review'
+import { PERMISSION_ACCESS_REQUEST_DECIDED_EVENT } from '@/ee/access-requests/lib/notification-events'
const principal = { kind: 'session', userId: 'admin', sessionId: 'session' } as const
const input = { organizationId: 'organization', requestId: 'request' }
@@ -176,7 +174,6 @@ beforeEach(() => {
})
mocks.membership.mockResolvedValue({ membershipId: 'membership', role: 'read' })
mocks.enabled.mockResolvedValue(true)
- mocks.featureEnabled.mockResolvedValue(true)
mocks.enterprise.mockResolvedValue(true)
mocks.catalog.mockResolvedValue(catalog)
mocks.deploymentReason.mockReturnValue(null)
diff --git a/apps/sim/lib/permission-access-requests/application/review.ts b/apps/sim/ee/access-requests/lib/application/review.ts
similarity index 93%
rename from apps/sim/lib/permission-access-requests/application/review.ts
rename to apps/sim/ee/access-requests/lib/application/review.ts
index 630cd7d4fca..e1a45306dc3 100644
--- a/apps/sim/lib/permission-access-requests/application/review.ts
+++ b/apps/sim/ee/access-requests/lib/application/review.ts
@@ -9,36 +9,36 @@ import type { WorkspaceUseCaseAuditEntry } from '@/lib/core/application/authoriz
import { OrchestrationError } from '@/lib/core/orchestration/types'
import { enqueueOutboxEvent } from '@/lib/core/outbox/service'
import type { DbOrTx } from '@/lib/db/types'
-import { loadAccessRequestMembership } from '@/lib/permission-access-requests/application/authorization'
-import { defineAuthorizedAccessRequestUseCase } from '@/lib/permission-access-requests/application/authorized-use-case'
-import { accessRequestOperations } from '@/lib/permission-access-requests/application/operations'
+import { acquirePermissionGroupOrgLock } from '@/lib/permission-groups/locks'
+import { loadAccessRequestMembership } from '@/ee/access-requests/lib/application/authorization'
+import { defineAuthorizedAccessRequestUseCase } from '@/ee/access-requests/lib/application/authorized-use-case'
+import { accessRequestOperations } from '@/ee/access-requests/lib/application/operations'
import {
type PreparedAccessRequestPolicy,
prepareAccessRequestPolicy,
-} from '@/lib/permission-access-requests/application/prepare'
-import { loadAccessRequestGroupImpact } from '@/lib/permission-access-requests/impact'
-import { PERMISSION_ACCESS_REQUEST_DECIDED_EVENT } from '@/lib/permission-access-requests/notification-events'
+} from '@/ee/access-requests/lib/application/prepare'
+import { loadAccessRequestGroupImpact } from '@/ee/access-requests/lib/impact'
+import { PERMISSION_ACCESS_REQUEST_DECIDED_EVENT } from '@/ee/access-requests/lib/notification-events'
import {
evaluateAccessRequestTarget,
loadAccessRequestPolicy,
loadMemberLimit,
-} from '@/lib/permission-access-requests/policy'
+} from '@/ee/access-requests/lib/policy'
import {
loadStoredAccessRequest,
presentAccessRequest,
type StoredAccessRequest,
-} from '@/lib/permission-access-requests/repository'
+} from '@/ee/access-requests/lib/repository'
import {
storedAccessRequestDecisionSchema,
storedAccessRequestTargetSchema,
-} from '@/lib/permission-access-requests/schemas'
-import { isAccessRequestEnabled } from '@/lib/permission-access-requests/settings'
+} from '@/ee/access-requests/lib/schemas'
+import { isAccessRequestEnabled } from '@/ee/access-requests/lib/settings'
+import type { AccessRequestScope } from '@/ee/access-requests/lib/targets'
import type {
AccessRequestPreview,
ResolveAccessRequestDecision,
-} from '@/lib/permission-access-requests/types'
-import type { AccessRequestScope } from '@/lib/permission-groups/access-requests/targets'
-import { acquirePermissionGroupOrgLock } from '@/lib/permission-groups/locks'
+} from '@/ee/access-requests/lib/types'
interface ReviewInput {
organizationId: string
@@ -139,7 +139,7 @@ async function loadReviewPreview(
catalog,
currentPolicy
)
- const enabled = await isAccessRequestEnabled(row.organizationId, executor, prepared.globalEnabled)
+ const enabled = await isAccessRequestEnabled(row.organizationId, executor)
const audience = policy.group
? await loadAccessRequestGroupImpact(
executor,
diff --git a/apps/sim/lib/permission-access-requests/catalog-registry.ts b/apps/sim/ee/access-requests/lib/catalog-registry.ts
similarity index 99%
rename from apps/sim/lib/permission-access-requests/catalog-registry.ts
rename to apps/sim/ee/access-requests/lib/catalog-registry.ts
index c3678f3ae4a..bb45379fac7 100644
--- a/apps/sim/lib/permission-access-requests/catalog-registry.ts
+++ b/apps/sim/ee/access-requests/lib/catalog-registry.ts
@@ -11,14 +11,6 @@ import {
isIntegrationDeploymentAvailableForVisibility,
isOAuthServiceDeploymentAvailable,
} from '@/lib/integrations/availability.server'
-import {
- type AccessRequestCatalog,
- type AccessRequestCatalogItem,
- type AccessRequestModelItem,
- type AccessRequestTarget,
- type AccessRequestToolItem,
- createAccessRequestCatalog,
-} from '@/lib/permission-groups/access-requests/targets'
import {
resolveAccessControlBlockType,
toAccessControlAllowlist,
@@ -26,6 +18,14 @@ import {
import { getBlockRegistry } from '@/blocks/registry'
import { isHiddenUnder } from '@/blocks/visibility/context'
import { CONNECTOR_META_REGISTRY } from '@/connectors/registry'
+import {
+ type AccessRequestCatalog,
+ type AccessRequestCatalogItem,
+ type AccessRequestModelItem,
+ type AccessRequestTarget,
+ type AccessRequestToolItem,
+ createAccessRequestCatalog,
+} from '@/ee/access-requests/lib/targets'
import { getStaticProviderModels, PROVIDER_DEFINITIONS } from '@/providers/models'
import { filterBlacklistedModels } from '@/providers/utils'
import { getToolMetadata } from '@/tools/metadata'
diff --git a/apps/sim/lib/permission-access-requests/catalog.test.ts b/apps/sim/ee/access-requests/lib/catalog.test.ts
similarity index 99%
rename from apps/sim/lib/permission-access-requests/catalog.test.ts
rename to apps/sim/ee/access-requests/lib/catalog.test.ts
index ad85beb35d3..c0c81cfc667 100644
--- a/apps/sim/lib/permission-access-requests/catalog.test.ts
+++ b/apps/sim/ee/access-requests/lib/catalog.test.ts
@@ -94,17 +94,17 @@ vi.mock('@/connectors/registry', () => ({
},
}))
+import { isBlockTypeAccessControlExempt } from '@/lib/permission-groups/block-access'
+import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields'
import {
getAccessRequestDeploymentUnavailableReason,
listAccessRequestTargets,
loadAccessRequestCatalog,
-} from '@/lib/permission-access-requests/catalog'
+} from '@/ee/access-requests/lib/catalog'
import {
buildAccessRequestPolicyDelta,
validateAccessRequestTarget,
-} from '@/lib/permission-groups/access-requests/targets'
-import { isBlockTypeAccessControlExempt } from '@/lib/permission-groups/block-access'
-import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields'
+} from '@/ee/access-requests/lib/targets'
const context = { userId: 'viewer', organizationId: 'org', workspaceId: 'ws' }
diff --git a/apps/sim/lib/permission-access-requests/catalog.ts b/apps/sim/ee/access-requests/lib/catalog.ts
similarity index 93%
rename from apps/sim/lib/permission-access-requests/catalog.ts
rename to apps/sim/ee/access-requests/lib/catalog.ts
index 983be1eda05..e6442f3b139 100644
--- a/apps/sim/lib/permission-access-requests/catalog.ts
+++ b/apps/sim/ee/access-requests/lib/catalog.ts
@@ -6,14 +6,14 @@ import {
isSandboxesEnabled,
isSsoEnabled,
} from '@/lib/core/config/env-flags'
-import type { AccessRequestCatalogContext } from '@/lib/permission-access-requests/catalog-registry'
+import { PLATFORM_FEATURES } from '@/lib/permission-groups/features'
+import { FILE_SHARE_AUTH_TYPES } from '@/lib/permission-groups/fields'
+import type { AccessRequestCatalogContext } from '@/ee/access-requests/lib/catalog-registry'
import {
type AccessRequestCatalog,
type AccessRequestTarget,
createAccessRequestCatalog,
-} from '@/lib/permission-groups/access-requests/targets'
-import { PLATFORM_FEATURES } from '@/lib/permission-groups/features'
-import { FILE_SHARE_AUTH_TYPES } from '@/lib/permission-groups/fields'
+} from '@/ee/access-requests/lib/targets'
/** Small navigation and credit-limit checks never load or enumerate the integration registries. */
export async function loadAccessRequestCatalog(
@@ -32,7 +32,7 @@ export async function loadAccessRequestCatalog(
knowledgeConnectors: [],
})
const { loadAccessRequestRegistryCatalog } = await import(
- '@/lib/permission-access-requests/catalog-registry'
+ '@/ee/access-requests/lib/catalog-registry'
)
return loadAccessRequestRegistryCatalog(context, targetKind)
}
diff --git a/apps/sim/lib/permission-access-requests/constants.ts b/apps/sim/ee/access-requests/lib/constants.ts
similarity index 100%
rename from apps/sim/lib/permission-access-requests/constants.ts
rename to apps/sim/ee/access-requests/lib/constants.ts
diff --git a/apps/sim/lib/permission-access-requests/impact.postgres.test.ts b/apps/sim/ee/access-requests/lib/impact.postgres.test.ts
similarity index 99%
rename from apps/sim/lib/permission-access-requests/impact.postgres.test.ts
rename to apps/sim/ee/access-requests/lib/impact.postgres.test.ts
index 3f9eb90359a..bd36ae5dd62 100644
--- a/apps/sim/lib/permission-access-requests/impact.postgres.test.ts
+++ b/apps/sim/ee/access-requests/lib/impact.postgres.test.ts
@@ -5,7 +5,7 @@ import { generateId } from '@sim/utils/id'
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import { describe, expect, it, vi } from 'vitest'
-import { loadAccessRequestGroupImpact } from '@/lib/permission-access-requests/impact'
+import { loadAccessRequestGroupImpact } from '@/ee/access-requests/lib/impact'
vi.unmock('@sim/db/schema')
vi.unmock('drizzle-orm')
diff --git a/apps/sim/lib/permission-access-requests/impact.ts b/apps/sim/ee/access-requests/lib/impact.ts
similarity index 98%
rename from apps/sim/lib/permission-access-requests/impact.ts
rename to apps/sim/ee/access-requests/lib/impact.ts
index 2a0ae391b48..66199e0e4a1 100644
--- a/apps/sim/lib/permission-access-requests/impact.ts
+++ b/apps/sim/ee/access-requests/lib/impact.ts
@@ -8,7 +8,7 @@ import {
} from '@sim/db/schema'
import { and, count, eq, inArray, isNull, or, type SQL, sql } from 'drizzle-orm'
import type { DbOrTx } from '@/lib/db/types'
-import type { AccessRequestImpact } from '@/lib/permission-access-requests/types'
+import type { AccessRequestImpact } from '@/ee/access-requests/lib/types'
/** Order-independent change detector with fixed-size aggregate state instead of sorted row strings. */
function membershipRevision(value: SQL): SQL {
diff --git a/apps/sim/lib/permission-access-requests/notification-events.ts b/apps/sim/ee/access-requests/lib/notification-events.ts
similarity index 100%
rename from apps/sim/lib/permission-access-requests/notification-events.ts
rename to apps/sim/ee/access-requests/lib/notification-events.ts
diff --git a/apps/sim/lib/permission-access-requests/notifications.test.ts b/apps/sim/ee/access-requests/lib/notifications.test.ts
similarity index 97%
rename from apps/sim/lib/permission-access-requests/notifications.test.ts
rename to apps/sim/ee/access-requests/lib/notifications.test.ts
index 9d11dda7fac..2ecee67538f 100644
--- a/apps/sim/lib/permission-access-requests/notifications.test.ts
+++ b/apps/sim/ee/access-requests/lib/notifications.test.ts
@@ -25,19 +25,19 @@ vi.mock('@/lib/messaging/email/mailer', () => ({
sendEmail: mockSend,
hasEmailService: mockHasEmailService,
}))
-vi.mock('@/lib/permission-access-requests/application/authorization', () => ({
+vi.mock('@/ee/access-requests/lib/application/authorization', () => ({
loadAccessRequestMembership: mockMembership,
}))
vi.mock('@/lib/core/utils/urls', () => ({ getBaseUrl: () => 'https://sim.example' }))
-vi.mock('@/lib/permission-access-requests/settings', () => ({
+vi.mock('@/ee/access-requests/lib/settings', () => ({
isAccessRequestEnabled: mockEnabled,
}))
import {
PERMISSION_ACCESS_REQUEST_CREATED_EVENT,
PERMISSION_ACCESS_REQUEST_DECIDED_EVENT,
-} from '@/lib/permission-access-requests/notification-events'
-import { permissionAccessRequestOutboxHandlers } from '@/lib/permission-access-requests/notifications'
+} from '@/ee/access-requests/lib/notification-events'
+import { permissionAccessRequestOutboxHandlers } from '@/ee/access-requests/lib/notifications'
const request = {
id: 'request-one',
diff --git a/apps/sim/lib/permission-access-requests/notifications.ts b/apps/sim/ee/access-requests/lib/notifications.ts
similarity index 96%
rename from apps/sim/lib/permission-access-requests/notifications.ts
rename to apps/sim/ee/access-requests/lib/notifications.ts
index 5516dde5dd7..0ef80c6ae7f 100644
--- a/apps/sim/lib/permission-access-requests/notifications.ts
+++ b/apps/sim/ee/access-requests/lib/notifications.ts
@@ -13,12 +13,12 @@ import {
} from '@/lib/core/outbox/service'
import { getBaseUrl } from '@/lib/core/utils/urls'
import { hasEmailService, sendEmail } from '@/lib/messaging/email/mailer'
-import { loadAccessRequestMembership } from '@/lib/permission-access-requests/application/authorization'
+import { loadAccessRequestMembership } from '@/ee/access-requests/lib/application/authorization'
import {
PERMISSION_ACCESS_REQUEST_CREATED_EVENT,
PERMISSION_ACCESS_REQUEST_DECIDED_EVENT,
-} from '@/lib/permission-access-requests/notification-events'
-import { isAccessRequestEnabled } from '@/lib/permission-access-requests/settings'
+} from '@/ee/access-requests/lib/notification-events'
+import { isAccessRequestEnabled } from '@/ee/access-requests/lib/settings'
const logger = createLogger('PermissionAccessRequestNotifications')
const ADMIN_RECIPIENT_PAGE_SIZE = 50
diff --git a/apps/sim/lib/permission-access-requests/policy.ts b/apps/sim/ee/access-requests/lib/policy.ts
similarity index 92%
rename from apps/sim/lib/permission-access-requests/policy.ts
rename to apps/sim/ee/access-requests/lib/policy.ts
index 29c4459f2c3..31bac8dc673 100644
--- a/apps/sim/lib/permission-access-requests/policy.ts
+++ b/apps/sim/ee/access-requests/lib/policy.ts
@@ -5,12 +5,10 @@ import { isOrganizationOnEnterprisePlan } from '@/lib/billing/core/subscription'
import { dollarsToCredits } from '@/lib/billing/credits/conversion'
import { isAccessControlEnabled, isHosted } from '@/lib/core/config/env-flags'
import type { DbOrTx } from '@/lib/db/types'
-import type { AccessRequestContext } from '@/lib/permission-access-requests/application/authorization'
-import { getAccessRequestDeploymentUnavailableReason } from '@/lib/permission-access-requests/catalog'
-import type {
- AccessRequestScope,
- AccessRequestTarget,
-} from '@/lib/permission-groups/access-requests/targets'
+import { resolveDefaultGroup, resolveWorkspaceGroup } from '@/lib/permission-groups/resolve.server'
+import type { AccessRequestContext } from '@/ee/access-requests/lib/application/authorization'
+import { getAccessRequestDeploymentUnavailableReason } from '@/ee/access-requests/lib/catalog'
+import type { AccessRequestScope, AccessRequestTarget } from '@/ee/access-requests/lib/targets'
import {
type AccessRequestCatalog,
buildAccessRequestPolicyDelta,
@@ -18,8 +16,7 @@ import {
isAccessRequestTargetDenied,
isAccessRequestTargetInScope,
validateAccessRequestTarget,
-} from '@/lib/permission-groups/access-requests/targets'
-import { resolveDefaultGroup, resolveWorkspaceGroup } from '@/lib/permission-groups/resolve.server'
+} from '@/ee/access-requests/lib/targets'
export async function loadMemberLimit(
executor: DbOrTx,
diff --git a/apps/sim/lib/permission-access-requests/repository.postgres.test.ts b/apps/sim/ee/access-requests/lib/repository.postgres.test.ts
similarity index 97%
rename from apps/sim/lib/permission-access-requests/repository.postgres.test.ts
rename to apps/sim/ee/access-requests/lib/repository.postgres.test.ts
index ba9e215772d..cce7027acde 100644
--- a/apps/sim/lib/permission-access-requests/repository.postgres.test.ts
+++ b/apps/sim/ee/access-requests/lib/repository.postgres.test.ts
@@ -5,7 +5,7 @@ import { and, eq } from 'drizzle-orm'
import { drizzle } from 'drizzle-orm/postgres-js'
import postgres from 'postgres'
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'
-import { listAccessRequestRecords } from '@/lib/permission-access-requests/repository'
+import { listAccessRequestRecords } from '@/ee/access-requests/lib/repository'
vi.unmock('@sim/db/schema')
vi.unmock('drizzle-orm')
diff --git a/apps/sim/lib/permission-access-requests/repository.ts b/apps/sim/ee/access-requests/lib/repository.ts
similarity index 95%
rename from apps/sim/lib/permission-access-requests/repository.ts
rename to apps/sim/ee/access-requests/lib/repository.ts
index ce13fc5748a..2e651e0e1d2 100644
--- a/apps/sim/lib/permission-access-requests/repository.ts
+++ b/apps/sim/ee/access-requests/lib/repository.ts
@@ -3,8 +3,8 @@ import { and, count, desc, eq, ilike, or, type SQL } from 'drizzle-orm'
import { escapeLikePattern } from '@/lib/api/list-query'
import { OrchestrationError } from '@/lib/core/orchestration/types'
import type { DbOrTx } from '@/lib/db/types'
-import { storedAccessRequestTargetSchema } from '@/lib/permission-access-requests/schemas'
-import type { AccessRequestList, AccessRequestRecord } from '@/lib/permission-access-requests/types'
+import { storedAccessRequestTargetSchema } from '@/ee/access-requests/lib/schemas'
+import type { AccessRequestList, AccessRequestRecord } from '@/ee/access-requests/lib/types'
export type StoredAccessRequest = typeof permissionAccessRequest.$inferSelect
diff --git a/apps/sim/lib/permission-access-requests/schemas.test.ts b/apps/sim/ee/access-requests/lib/schemas.test.ts
similarity index 96%
rename from apps/sim/lib/permission-access-requests/schemas.test.ts
rename to apps/sim/ee/access-requests/lib/schemas.test.ts
index d98cf87162a..234e21edc1c 100644
--- a/apps/sim/lib/permission-access-requests/schemas.test.ts
+++ b/apps/sim/ee/access-requests/lib/schemas.test.ts
@@ -2,11 +2,11 @@
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
-import { storedAccessRequestPolicyChangeSchema } from '@/lib/permission-access-requests/schemas'
import {
DEFAULT_PERMISSION_GROUP_CONFIG,
PERMISSION_GROUP_FIELDS,
} from '@/lib/permission-groups/fields'
+import { storedAccessRequestPolicyChangeSchema } from '@/ee/access-requests/lib/schemas'
describe('stored access request policy changes', () => {
it('accepts unchanged canonical values for every field', () => {
diff --git a/apps/sim/lib/permission-access-requests/schemas.ts b/apps/sim/ee/access-requests/lib/schemas.ts
similarity index 98%
rename from apps/sim/lib/permission-access-requests/schemas.ts
rename to apps/sim/ee/access-requests/lib/schemas.ts
index 5e17319cd38..2ce98b701af 100644
--- a/apps/sim/lib/permission-access-requests/schemas.ts
+++ b/apps/sim/ee/access-requests/lib/schemas.ts
@@ -1,7 +1,7 @@
import { z } from 'zod'
-import type { AccessRequestTarget as DomainAccessRequestTarget } from '@/lib/permission-groups/access-requests/targets'
import { PLATFORM_FEATURES } from '@/lib/permission-groups/features'
import { FILE_SHARE_AUTH_TYPES, PERMISSION_GROUP_FIELDS } from '@/lib/permission-groups/fields'
+import type { AccessRequestTarget as DomainAccessRequestTarget } from '@/ee/access-requests/lib/targets'
const targetIdSchema = z.string().min(1, 'Target ID cannot be empty').max(512)
const fingerprintSchema = z.string().min(1, 'A current preview is required').max(128)
diff --git a/apps/sim/ee/access-requests/lib/settings.test.ts b/apps/sim/ee/access-requests/lib/settings.test.ts
new file mode 100644
index 00000000000..8a540763fcb
--- /dev/null
+++ b/apps/sim/ee/access-requests/lib/settings.test.ts
@@ -0,0 +1,48 @@
+/**
+ * @vitest-environment node
+ */
+import { organizationAccessRequestSettings } from '@sim/db/schema'
+import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing'
+import { beforeEach, describe, expect, it } from 'vitest'
+import {
+ isAccessRequestEnabled,
+ readAccessRequestSettings,
+} from '@/ee/access-requests/lib/settings'
+
+beforeEach(() => {
+ resetDbChainMock()
+})
+
+describe('permission access request settings', () => {
+ it('defaults the organization preference on when no settings row exists', async () => {
+ queueTableRows(organizationAccessRequestSettings, [])
+
+ await expect(readAccessRequestSettings('organization-one')).resolves.toEqual({
+ allowRequests: true,
+ })
+ expect(dbChainMockFns.limit).toHaveBeenCalledWith(1)
+ expect(dbChainMockFns.where).toHaveBeenCalledWith({
+ type: 'eq',
+ left: organizationAccessRequestSettings.organizationId,
+ right: 'organization-one',
+ })
+ })
+
+ it('honors an organization opt-out', async () => {
+ queueTableRows(organizationAccessRequestSettings, [{ allowRequests: false }])
+
+ await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(false)
+ })
+
+ it('preserves an explicit enabled preference', async () => {
+ queueTableRows(organizationAccessRequestSettings, [{ allowRequests: true }])
+
+ await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(true)
+ })
+
+ it('does not reinterpret a failed settings lookup as permission to submit', async () => {
+ dbChainMockFns.limit.mockRejectedValueOnce(new Error('database unavailable'))
+
+ await expect(isAccessRequestEnabled('organization-one')).rejects.toThrow('database unavailable')
+ })
+})
diff --git a/apps/sim/lib/permission-access-requests/settings.ts b/apps/sim/ee/access-requests/lib/settings.ts
similarity index 71%
rename from apps/sim/lib/permission-access-requests/settings.ts
rename to apps/sim/ee/access-requests/lib/settings.ts
index f2b35394116..24f7daf2585 100644
--- a/apps/sim/lib/permission-access-requests/settings.ts
+++ b/apps/sim/ee/access-requests/lib/settings.ts
@@ -1,7 +1,6 @@
import { db } from '@sim/db'
import { organizationAccessRequestSettings } from '@sim/db/schema'
import { eq } from 'drizzle-orm'
-import { isFeatureEnabled } from '@/lib/core/config/feature-flags'
import type { DbOrTx } from '@/lib/db/types'
/** Missing settings preserve the default-on organization preference. */
@@ -14,13 +13,10 @@ export async function readAccessRequestSettings(organizationId: string, executor
return { allowRequests: row?.allowRequests ?? true }
}
-/** The rollout flag is evaluated globally; organization preferences can only narrow it. */
+/** Access requests are on unless the organization has opted out. */
export async function isAccessRequestEnabled(
organizationId: string,
- executor: DbOrTx = db,
- enabledAtAdmission?: boolean
+ executor: DbOrTx = db
): Promise {
- if (enabledAtAdmission === false || !(await isFeatureEnabled('permission-access-requests')))
- return false
return (await readAccessRequestSettings(organizationId, executor)).allowRequests
}
diff --git a/apps/sim/lib/permission-groups/access-requests/targets.test.ts b/apps/sim/ee/access-requests/lib/targets.test.ts
similarity index 99%
rename from apps/sim/lib/permission-groups/access-requests/targets.test.ts
rename to apps/sim/ee/access-requests/lib/targets.test.ts
index d5ac0b2db25..43d59c1a081 100644
--- a/apps/sim/lib/permission-groups/access-requests/targets.test.ts
+++ b/apps/sim/ee/access-requests/lib/targets.test.ts
@@ -2,6 +2,8 @@
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
+import { CAPABILITY_RULES } from '@/lib/permission-groups/capabilities'
+import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields'
import {
type AccessRequestTarget,
buildAccessRequestPolicyDelta,
@@ -11,9 +13,7 @@ import {
isAccessRequestTargetDenied,
isAccessRequestTargetInScope,
validateAccessRequestTarget,
-} from '@/lib/permission-groups/access-requests/targets'
-import { CAPABILITY_RULES } from '@/lib/permission-groups/capabilities'
-import { DEFAULT_PERMISSION_GROUP_CONFIG } from '@/lib/permission-groups/fields'
+} from '@/ee/access-requests/lib/targets'
const catalog = createAccessRequestCatalog({
integrations: [
diff --git a/apps/sim/lib/permission-groups/access-requests/targets.ts b/apps/sim/ee/access-requests/lib/targets.ts
similarity index 100%
rename from apps/sim/lib/permission-groups/access-requests/targets.ts
rename to apps/sim/ee/access-requests/lib/targets.ts
diff --git a/apps/sim/lib/permission-access-requests/types.ts b/apps/sim/ee/access-requests/lib/types.ts
similarity index 90%
rename from apps/sim/lib/permission-access-requests/types.ts
rename to apps/sim/ee/access-requests/lib/types.ts
index 9acb355d778..33f6e18e476 100644
--- a/apps/sim/lib/permission-access-requests/types.ts
+++ b/apps/sim/ee/access-requests/lib/types.ts
@@ -1,8 +1,5 @@
-import type { AccessRequestDecision } from '@/lib/permission-access-requests/schemas'
-import type {
- AccessRequestScope,
- AccessRequestTarget,
-} from '@/lib/permission-groups/access-requests/targets'
+import type { AccessRequestDecision } from '@/ee/access-requests/lib/schemas'
+import type { AccessRequestScope, AccessRequestTarget } from '@/ee/access-requests/lib/targets'
export type AccessRequestStatus = 'pending' | 'fulfilled' | 'declined' | 'cancelled' | 'closed'
diff --git a/apps/sim/lib/api/contracts/access-requests.ts b/apps/sim/lib/api/contracts/access-requests.ts
index 53f40b4f172..4532bbf6524 100644
--- a/apps/sim/lib/api/contracts/access-requests.ts
+++ b/apps/sim/lib/api/contracts/access-requests.ts
@@ -1,22 +1,22 @@
import { z } from 'zod'
import { organizationIdSchema, workspaceIdSchema } from '@/lib/api/contracts/primitives'
import { defineRouteContract } from '@/lib/api/contracts/types'
+import { PERMISSION_GROUP_FIELDS } from '@/lib/permission-groups/fields'
import {
ACCESS_REQUEST_MAX_ID_LENGTH,
ACCESS_REQUEST_MAX_OFFSET,
ACCESS_REQUEST_MAX_SEARCH_LENGTH,
-} from '@/lib/permission-access-requests/constants'
+} from '@/ee/access-requests/lib/constants'
import {
storedAccessRequestDecisionSchema,
storedAccessRequestPolicyChangeSchema,
storedAccessRequestPolicyValueSchema,
storedAccessRequestTargetSchema,
-} from '@/lib/permission-access-requests/schemas'
+} from '@/ee/access-requests/lib/schemas'
import {
ACCESS_REQUEST_TARGET_KINDS,
type AccessRequestScope as DomainAccessRequestScope,
-} from '@/lib/permission-groups/access-requests/targets'
-import { PERMISSION_GROUP_FIELDS } from '@/lib/permission-groups/fields'
+} from '@/ee/access-requests/lib/targets'
export const ACCESS_REQUEST_STATUSES = [
'pending',
diff --git a/apps/sim/lib/core/config/env.ts b/apps/sim/lib/core/config/env.ts
index 8d61dba5005..6f7e4974c84 100644
--- a/apps/sim/lib/core/config/env.ts
+++ b/apps/sim/lib/core/config/env.ts
@@ -626,7 +626,6 @@ export const env = createEnv({
FORKING_ENABLED: z.boolean().optional(), // Enable workspace forking on self-hosted (bypasses hosted requirements)
TABLES_V2_API: z.boolean().optional(), // Enable the v2 tables HTTP API (public /api/v2/tables + internal /api/table/[tableId]/query predicate-grammar route)
TABLE_ROW_TTL: z.boolean().optional(),
- PERMISSION_ACCESS_REQUESTS_ENABLED: z.boolean().optional(),
CREDENTIAL_GROUPS: z.boolean().optional(), // Enable enterprise Credential Groups globally
KNOWLEDGE_MEMBER_ACCESS: z.boolean().optional(), // Enable per-member knowledge connectors and hybrid-by-default retrieval globally
diff --git a/apps/sim/lib/core/config/feature-flags.test.ts b/apps/sim/lib/core/config/feature-flags.test.ts
index bd010a4f949..de18088049a 100644
--- a/apps/sim/lib/core/config/feature-flags.test.ts
+++ b/apps/sim/lib/core/config/feature-flags.test.ts
@@ -2,7 +2,7 @@
* @vitest-environment node
*/
import { resetEnvFlagsMock, setEnvFlags } from '@sim/testing'
-import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'
import type { FeatureFlagContext, FeatureFlagName } from '@/lib/core/config/feature-flags'
const { mockFetch, mockIsPlatformAdmin, envRef } = vi.hoisted(() => ({
@@ -13,7 +13,6 @@ const { mockFetch, mockIsPlatformAdmin, envRef } = vi.hoisted(() => ({
APPCONFIG_ENVIRONMENT: 'staging' as string | undefined,
TABLES_V2_API: undefined as boolean | undefined,
TABLE_ROW_TTL: undefined as boolean | undefined,
- PERMISSION_ACCESS_REQUESTS_ENABLED: undefined as boolean | undefined,
CREDENTIAL_GROUPS: undefined as boolean | undefined,
KNOWLEDGE_MEMBER_ACCESS: undefined as boolean | undefined,
SLACK_SEARCH_SHARED_APP: undefined as boolean | undefined,
@@ -337,26 +336,3 @@ describe('table-row-ttl flag', () => {
expect(await isFeatureEnabled('table-row-ttl')).toBe(true)
})
})
-
-describe('permission access request rollout', () => {
- beforeEach(() => {
- vi.clearAllMocks()
- setEnvFlags({ isAppConfigEnabled: false })
- envRef.PERMISSION_ACCESS_REQUESTS_ENABLED = undefined
- })
- afterEach(() => {
- envRef.PERMISSION_ACCESS_REQUESTS_ENABLED = undefined
- })
- it('defaults off and can be enabled with the fallback secret', async () => {
- expect(await isFeatureEnabled('permission-access-requests')).toBe(false)
- envRef.PERMISSION_ACCESS_REQUESTS_ENABLED = true
- expect(await isFeatureEnabled('permission-access-requests')).toBe(true)
- expect(mockFetch).not.toHaveBeenCalled()
- })
- it('uses a global AppConfig rule without organization targeting', async () => {
- withAppConfig({ 'permission-access-requests': { enabled: false, orgIds: ['org'] } })
- expect(await isFeatureEnabled('permission-access-requests')).toBe(false)
- withAppConfig({ 'permission-access-requests': { enabled: true } })
- expect(await isFeatureEnabled('permission-access-requests')).toBe(true)
- })
-})
diff --git a/apps/sim/lib/core/config/feature-flags.ts b/apps/sim/lib/core/config/feature-flags.ts
index 597001b5cc2..2a94f48ee09 100644
--- a/apps/sim/lib/core/config/feature-flags.ts
+++ b/apps/sim/lib/core/config/feature-flags.ts
@@ -46,11 +46,6 @@ interface FeatureFlagDefinition {
/** The single registry of known flags. To add a flag, add one entry here. */
const FEATURE_FLAGS = {
- 'permission-access-requests': {
- description:
- 'Enable permission and member usage-cap requests globally. Organizations can opt out in access control settings.',
- fallback: 'PERMISSION_ACCESS_REQUESTS_ENABLED',
- },
'slack-search-shared-app': {
description:
'Enable the official shared Slack app for existing Search customers. Supports orgId ' +
diff --git a/apps/sim/lib/core/outbox/processor.test.ts b/apps/sim/lib/core/outbox/processor.test.ts
index d20af17bc58..6ad93cc80fa 100644
--- a/apps/sim/lib/core/outbox/processor.test.ts
+++ b/apps/sim/lib/core/outbox/processor.test.ts
@@ -37,7 +37,7 @@ vi.mock('@/lib/mothership/inbox/cleanup-outbox', () => ({ inboxCleanupOutboxHand
vi.mock('@/lib/organizations/resource-cleanup', () => ({
organizationResourceCleanupOutboxHandlers: {},
}))
-vi.mock('@/lib/permission-access-requests/notifications', () => ({
+vi.mock('@/ee/access-requests/lib/notifications', () => ({
permissionAccessRequestOutboxHandlers: {},
}))
vi.mock('@/lib/uploads/contexts/workspace/workspace-file-live-doc-outbox', () => ({
diff --git a/apps/sim/lib/core/outbox/processor.ts b/apps/sim/lib/core/outbox/processor.ts
index 464460579bc..41e625b118f 100644
--- a/apps/sim/lib/core/outbox/processor.ts
+++ b/apps/sim/lib/core/outbox/processor.ts
@@ -20,12 +20,12 @@ import { knowledgeDocumentProcessingOutboxHandlers } from '@/lib/knowledge/docum
import { recoverKnowledgeDocumentProcessing } from '@/lib/knowledge/documents/processing-recovery'
import { inboxCleanupOutboxHandlers } from '@/lib/mothership/inbox/cleanup-outbox'
import { organizationResourceCleanupOutboxHandlers } from '@/lib/organizations/resource-cleanup'
-import { permissionAccessRequestOutboxHandlers } from '@/lib/permission-access-requests/notifications'
import { workspaceFileLiveDocOutboxHandlers } from '@/lib/uploads/contexts/workspace/workspace-file-live-doc-outbox'
import { workspaceFileStorageCleanupOutboxHandlers } from '@/lib/uploads/contexts/workspace/workspace-file-storage-cleanup-outbox'
import { workflowDeploymentOutboxHandlers } from '@/lib/workflows/deployment-outbox'
import { invitationMigrationOutboxHandlers } from '@/lib/workspaces/admin-move'
import { workspaceOperationOutboxHandlers } from '@/lib/workspaces/operations/outbox'
+import { permissionAccessRequestOutboxHandlers } from '@/ee/access-requests/lib/notifications'
import { forkContentOutboxHandlers } from '@/ee/workspace-forking/application/content-outbox'
import { reapStaleBackgroundWork } from '@/ee/workspace-forking/lib/background-work/store'
diff --git a/apps/sim/lib/permission-access-requests/settings.test.ts b/apps/sim/lib/permission-access-requests/settings.test.ts
deleted file mode 100644
index 69643b15c04..00000000000
--- a/apps/sim/lib/permission-access-requests/settings.test.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-/**
- * @vitest-environment node
- */
-import { organizationAccessRequestSettings } from '@sim/db/schema'
-import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing'
-import { beforeEach, describe, expect, it, vi } from 'vitest'
-
-const { mockIsFeatureEnabled } = vi.hoisted(() => ({ mockIsFeatureEnabled: vi.fn() }))
-
-vi.mock('@/lib/core/config/feature-flags', () => ({ isFeatureEnabled: mockIsFeatureEnabled }))
-
-import {
- isAccessRequestEnabled,
- readAccessRequestSettings,
-} from '@/lib/permission-access-requests/settings'
-
-beforeEach(() => {
- vi.clearAllMocks()
- resetDbChainMock()
- mockIsFeatureEnabled.mockResolvedValue(true)
-})
-
-describe('permission access request settings', () => {
- it('defaults the organization preference on when no settings row exists', async () => {
- queueTableRows(organizationAccessRequestSettings, [])
-
- await expect(readAccessRequestSettings('organization-one')).resolves.toEqual({
- allowRequests: true,
- })
- expect(dbChainMockFns.limit).toHaveBeenCalledWith(1)
- expect(dbChainMockFns.where).toHaveBeenCalledWith({
- type: 'eq',
- left: organizationAccessRequestSettings.organizationId,
- right: 'organization-one',
- })
- })
-
- it('does not let the default-on preference bypass the global rollout flag', async () => {
- mockIsFeatureEnabled.mockResolvedValue(false)
-
- await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(false)
-
- expect(mockIsFeatureEnabled).toHaveBeenCalledExactlyOnceWith('permission-access-requests')
- expect(dbChainMockFns.select).not.toHaveBeenCalled()
- })
-
- it('enables requests when rollout is active and the organization has not opted out', async () => {
- queueTableRows(organizationAccessRequestSettings, [])
-
- await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(true)
- })
-
- it('rechecks rollout after an enabled admission snapshot', async () => {
- mockIsFeatureEnabled.mockResolvedValue(false)
-
- await expect(isAccessRequestEnabled('organization-one', undefined, true)).resolves.toBe(false)
-
- expect(mockIsFeatureEnabled).toHaveBeenCalledExactlyOnceWith('permission-access-requests')
- expect(dbChainMockFns.select).not.toHaveBeenCalled()
- })
-
- it('keeps a disabled admission snapshot denied even if rollout is now enabled', async () => {
- await expect(isAccessRequestEnabled('organization-one', undefined, false)).resolves.toBe(false)
-
- expect(mockIsFeatureEnabled).not.toHaveBeenCalled()
- expect(dbChainMockFns.select).not.toHaveBeenCalled()
- })
-
- it('requires the current organization preference after an enabled admission snapshot', async () => {
- queueTableRows(organizationAccessRequestSettings, [{ allowRequests: false }])
-
- await expect(isAccessRequestEnabled('organization-one', undefined, true)).resolves.toBe(false)
-
- expect(mockIsFeatureEnabled).toHaveBeenCalledExactlyOnceWith('permission-access-requests')
- expect(dbChainMockFns.select).toHaveBeenCalledTimes(1)
- })
-
- it('honors an organization opt-out while global rollout is active', async () => {
- queueTableRows(organizationAccessRequestSettings, [{ allowRequests: false }])
-
- await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(false)
- })
-
- it('preserves an explicit enabled preference', async () => {
- queueTableRows(organizationAccessRequestSettings, [{ allowRequests: true }])
-
- await expect(isAccessRequestEnabled('organization-one')).resolves.toBe(true)
- })
-
- it('does not reinterpret a failed settings lookup as permission to submit', async () => {
- dbChainMockFns.limit.mockRejectedValueOnce(new Error('database unavailable'))
-
- await expect(isAccessRequestEnabled('organization-one')).rejects.toThrow('database unavailable')
- })
-})
diff --git a/apps/sim/lib/settings/application/workspace-section-access.test.ts b/apps/sim/lib/settings/application/workspace-section-access.test.ts
index f1378edf865..77c804cd809 100644
--- a/apps/sim/lib/settings/application/workspace-section-access.test.ts
+++ b/apps/sim/lib/settings/application/workspace-section-access.test.ts
@@ -59,7 +59,7 @@ vi.mock('@/components/settings/navigation', () => ({
),
WORKSPACE_PERMISSION_CONFIG_KEYS: { secrets: 'hideSecretsTab' },
}))
-vi.mock('@/lib/permission-access-requests/settings', () => ({
+vi.mock('@/ee/access-requests/lib/settings', () => ({
isAccessRequestEnabled: mocks.isAccessRequestEnabled,
}))
vi.mock('@/lib/billing/core/subscription', () => ({
diff --git a/apps/sim/lib/settings/application/workspace-section-access.ts b/apps/sim/lib/settings/application/workspace-section-access.ts
index 01cca335dfe..ab8c8e2a6d4 100644
--- a/apps/sim/lib/settings/application/workspace-section-access.ts
+++ b/apps/sim/lib/settings/application/workspace-section-access.ts
@@ -12,7 +12,6 @@ import {
import { isOrganizationOnEnterprisePlan } from '@/lib/billing/core/subscription'
import { getDeploymentShape } from '@/lib/core/config/deployment-shape'
import { canOpenOrganizationSettingsSection } from '@/lib/organizations/settings-access'
-import { isAccessRequestEnabled } from '@/lib/permission-access-requests/settings'
import type { BooleanPermissionGroupConfigKey } from '@/lib/permission-groups/features'
import { isOrganizationPermissionRegimeActive } from '@/lib/permission-groups/resolve.server'
import { isPlatformAdmin } from '@/lib/permissions/super-user'
@@ -20,6 +19,7 @@ import { authorizeOrganizationSettingsSection } from '@/lib/settings/application
import { isCustomBlocksEligibleForOrganization } from '@/lib/workflows/custom-blocks/operations'
import { checkWorkspaceAccess } from '@/lib/workspaces/permissions/utils'
import { resolveVerifiedUserAccessControlContext } from '@/ee/access-control/utils/permission-check'
+import { isAccessRequestEnabled } from '@/ee/access-requests/lib/settings'
import { isForkingAvailableForWorkspace } from '@/ee/workspace-forking/lib/lineage/authz'
export type WorkspaceSettingsSectionAccess =
diff --git a/scripts/check-tool-registry-boundary.baseline.json b/scripts/check-tool-registry-boundary.baseline.json
index 9be3e4c4193..af6dad97f18 100644
--- a/scripts/check-tool-registry-boundary.baseline.json
+++ b/scripts/check-tool-registry-boundary.baseline.json
@@ -77,7 +77,7 @@
"app/workspace/[workspaceId]/access-requests/page.tsx": {
"modules": 45,
"gateways": {
- "apps/sim/components/access-requests/my-access-requests.tsx": 43
+ "apps/sim/ee/access-requests/components/my-access-requests.tsx": 43
}
},
"app/workspace/[workspaceId]/chat/[chatId]/error.tsx": {