-
Notifications
You must be signed in to change notification settings - Fork 106
Search contexts #273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Search contexts #273
Conversation
WalkthroughThis set of changes introduces the "search contexts" feature to the codebase, enabling users to define and use named groupings of repositories for more focused code searches. The update includes database schema migrations, configuration schema and type extensions, backend and UI logic to support context-aware searching, and comprehensive documentation for both configuration and usage. Additionally, the billing and entitlement systems are refactored and extended, centralizing support email addresses and improving error handling. The documentation navigation is updated to reflect new and expanded topics, and the licensing structure is clarified for both open-source and enterprise components. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant UI
participant Server
participant DB
User->>UI: Enter search query with context: prefix
UI->>Server: search({ query: "context:frontend ..." })
Server->>DB: Lookup search context "frontend"
DB-->>Server: Return list of repos in context
Server->>Server: Transform query to reposet:<repo1,repo2,...>
Server->>DB: Perform search within repo set
DB-->>Server: Return search results
Server-->>UI: Return results
UI-->>User: Display results
Assessment against linked issues
Suggested reviewers
Poem
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🔭 Outside diff range comments (1)
packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx (1)
265-277
:⚠️ Potential issueMissing
searchContextSuggestions
in dependency listFor the reasons above, please include
searchContextSuggestions
in the dependency array so React can refresh the memo when context suggestions arrive.
🧹 Nitpick comments (25)
packages/web/src/lib/constants.ts (1)
31-32
: Add default single-tenant organization name
The newSINGLE_TENANT_ORG_NAME
constant aligns with other single-tenant defaults, improving configurability. Consider whether this value should be configurable via environment variables or a config file in the future for added flexibility.package.json (1)
7-8
: Update workspace command syntax
Switching toyarn workspaces foreach -A run
ensures all workspaces (including private ones) execute thebuild
andtest
scripts. Confirm this change doesn’t introduce dependency ordering issues during build/test. You may also consider adding flags like--topological-run
to enforce execution order or--parallel
for speed.ee/LICENSE (1)
1-3
: Use consistent ASCII quotation marks
The license text currently uses curly quotes (“
/”
), which can cause encoding or parsing inconsistencies. Replace them with straight ASCII double quotes ("
) to improve portability.packages/web/src/ee/features/billing/components/checkout.tsx (1)
15-15
: Consistent import style for billing actions.Currently importing
createOnboardingSubscription
via a relative path ("../actions"
), while other EE billing components use absolute imports ("@/ee/features/billing/actions"
). For consistency and maintainability, consider switching to the absolute path:-import { createOnboardingSubscription } from "../actions"; +import { createOnboardingSubscription } from "@/ee/features/billing/actions";packages/web/src/env.mjs (1)
52-54
: New EE license key environment variable.The addition of
SOURCEBOT_EE_LICENSE_KEY
is appropriate for the enterprise features being implemented. Making it optional ensures the application can run without it for the open-source version.It might be helpful to include a brief comment explaining the purpose of this environment variable and how it relates to feature entitlements.
// EE License -SOURCEBOT_EE_LICENSE_KEY: z.string().optional(), +// Used to determine the current plan and entitlements for enterprise features +SOURCEBOT_EE_LICENSE_KEY: z.string().optional(),docs/self-hosting/license-key.mdx (1)
1-17
: Clear documentation for license key setupThe documentation provides concise instructions for activating a license key and explains the licensing model clearly.
Consider enhancing this documentation with:
- A list of specific features that require a license key (e.g., search contexts)
- A link to more detailed documentation about enterprise features
- Information about how to obtain a license key
This would provide users with a more complete understanding of the enterprise offerings without needing to visit the pricing page.
packages/web/src/features/entitlements/README.md (1)
1-9
: Grammar corrections needed in entitlements documentationThe README provides a clear explanation of the entitlements system, but has minor grammatical issues:
- Line 8: "a instance" should be "an instance" (vowel sound rule)
- Consider adding spacing after paragraphs for better readability
# Entitlements Entitlements control the availability of certain features dependent on the current plan. Entitlements are managed at the **instance** level. Some definitions: - `Plan`: A plan is a tier of features. Examples: `oss`, `cloud:team`, `self-hosted:enterprise`. -- `Entitlement`: An entitlement is a feature that is available to a instance. Examples: `search-contexts`, `billing`. +- `Entitlement`: An entitlement is a feature that is available to an instance. Examples: `search-contexts`, `billing`.🧰 Tools
🪛 LanguageTool
[uncategorized] ~7-~7: Loose punctuation mark.
Context: ...ce** level. Some definitions: -Plan
: A plan is a tier of features. Examples:...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~8-~8: Loose punctuation mark.
Context: ...self-hosted:enterprise. -
Entitlement`: An entitlement is a feature that is ava...(UNLIKELY_OPENING_PUNCTUATION)
[misspelling] ~8-~8: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...ement is a feature that is available to a instance. Examples:search-contexts
, ...(EN_A_VS_AN)
packages/web/src/features/entitlements/planProvider.tsx (1)
22-22
: Minor: Remove extra blank lineThere's an extra blank line at the end of the file. Consider removing it to maintain consistent file formatting.
}; -
docs/docs/more/syntax-reference.mdx (3)
5-5
: Fix verb tense in introductionThere's a verb tense issue in the introduction sentence.
-Sourcebot uses a powerful regex-based query language that enabled precise code search within large codebases. +Sourcebot uses a powerful regex-based query language that enables precise code search within large codebases.🧰 Tools
🪛 LanguageTool
[uncategorized] ~5-~5: This verb may not be in the correct tense. Consider changing the tense to fit the context better.
Context: ...owerful regex-based query language that enabled precise code search within large codeba...(AI_EN_LECTOR_REPLACEMENT_VERB_TENSE)
30-35
: Add missing commas after "By default" phrasesSeveral instances of "By default" are missing commas, which affects readability.
-Filter results from filepaths that match the regex. By default all files are searched. +Filter results from filepaths that match the regex. By default, all files are searched. -Filter results from repos that match the regex. By default all repos are searched. +Filter results from repos that match the regex. By default, all repos are searched. -Filter results from a specific branch or tag. By default **only** the default branch is searched. +Filter results from a specific branch or tag. By default, **only** the default branch is searched. -Filter results by language (as defined by [linguist](https://github.com/github-linguist/linguist/blob/main/lib/linguist/languages.yml)). By default all languages are searched. +Filter results by language (as defined by [linguist](https://github.com/github-linguist/linguist/blob/main/lib/linguist/languages.yml)). By default, all languages are searched.🧰 Tools
🪛 LanguageTool
[uncategorized] ~30-~30: Did you mean: “By default,”?
Context: ...ts from filepaths that match the regex. By default all files are searched. |file:README
...(BY_DEFAULT_COMMA)
[uncategorized] ~30-~30: A determiner appears to be missing. Consider inserting it.
Context: ...r results to filepaths that match regex/README/
file:"my file"
- Filter results to filepaths that ma...(AI_EN_LECTOR_MISSING_DETERMINER)
[uncategorized] ~31-~31: Did you mean: “By default,”?
Context: ...esults from repos that match the regex. By default all repos are searched. |repo:linux
...(BY_DEFAULT_COMMA)
[uncategorized] ~32-~32: Did you mean: “By default,”?
Context: ... results from a specific branch or tag. By default only the default branch is searched...(BY_DEFAULT_COMMA)
[uncategorized] ~33-~33: Did you mean: “By default,”?
Context: ...blob/main/lib/linguist/languages.yml)). By default all languages are searched. | `lang:Typ...(BY_DEFAULT_COMMA)
30-30
: Add missing article in example descriptionA determiner/article is missing in one of the examples.
-`file:README` - Filter results to filepaths that match regex `/README/` +`file:README` - Filter results to filepaths that match the regex `/README/`🧰 Tools
🪛 LanguageTool
[uncategorized] ~30-~30: Did you mean: “By default,”?
Context: ...ts from filepaths that match the regex. By default all files are searched. |file:README
...(BY_DEFAULT_COMMA)
[uncategorized] ~30-~30: A determiner appears to be missing. Consider inserting it.
Context: ...r results to filepaths that match regex/README/
file:"my file"
- Filter results to filepaths that ma...(AI_EN_LECTOR_MISSING_DETERMINER)
packages/web/src/features/entitlements/server.ts (3)
15-19
: Consider adding more specific error handling in the decoding function.The function correctly decodes and validates the license payload, but it would be beneficial to have more granular error handling to distinguish between different types of failures (JSON parsing errors vs schema validation errors).
const decodeLicenseKeyPayload = (payload: string) => { - const decodedPayload = base64Decode(payload); - const payloadJson = JSON.parse(decodedPayload); - return eeLicenseKeyPayloadSchema.parse(payloadJson); + try { + const decodedPayload = base64Decode(payload); + try { + const payloadJson = JSON.parse(decodedPayload); + return eeLicenseKeyPayloadSchema.parse(payloadJson); + } catch (error) { + throw new Error(`Invalid JSON in license key payload: ${error.message}`); + } + } catch (error) { + throw new Error(`Failed to decode base64 license key payload: ${error.message}`); + } }
26-27
: Use optional chaining as suggested by static analysis.The static analysis suggests using optional chaining for safer property access.
const licenseKey = env.SOURCEBOT_EE_LICENSE_KEY; -if (licenseKey && licenseKey.startsWith(eeLicenseKeyPrefix)) { +if (licenseKey?.startsWith(eeLicenseKeyPrefix)) {🧰 Tools
🪛 Biome (1.9.4)
[error] 27-27: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
21-47
: Consider implementing caching for plan determination.The
getPlan
function performs license validation on every call, which could be inefficient if called frequently. Consider implementing a caching mechanism to avoid redundant computation.+// Cache the plan to avoid redundant computation +let cachedPlan: Plan | null = null; +let planCacheTime = 0; +const PLAN_CACHE_TTL = 60 * 1000; // 1 minute in ms export const getPlan = (): Plan => { + // Return cached plan if available and not expired + const now = Date.now(); + if (cachedPlan && now - planCacheTime < PLAN_CACHE_TTL) { + return cachedPlan; + } + if (env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT) { - return "cloud:team"; + cachedPlan = "cloud:team"; + planCacheTime = now; + return cachedPlan; } const licenseKey = env.SOURCEBOT_EE_LICENSE_KEY; if (licenseKey?.startsWith(eeLicenseKeyPrefix)) { const payload = licenseKey.substring(eeLicenseKeyPrefix.length); try { const { expiryDate } = decodeLicenseKeyPayload(payload); if (expiryDate && new Date(expiryDate).getTime() < new Date().getTime()) { console.error(`The provided license key has expired. Falling back to oss plan. Please contact ${SOURCEBOT_SUPPORT_EMAIL} for support.`); - return "oss"; + cachedPlan = "oss"; + planCacheTime = now; + return cachedPlan; } - return "self-hosted:enterprise"; + cachedPlan = "self-hosted:enterprise"; + planCacheTime = now; + return cachedPlan; } catch (error) { console.error(`Failed to decode license key payload with error: ${error}`); console.info('Falling back to oss plan.'); - return "oss"; + cachedPlan = "oss"; + planCacheTime = now; + return cachedPlan; } } - return "oss"; + cachedPlan = "oss"; + planCacheTime = now; + return cachedPlan; }🧰 Tools
🪛 Biome (1.9.4)
[error] 27-27: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
docs/self-hosting/more/search-contexts.mdx (2)
17-17
: Minor grammar improvement suggested.The phrase "inside of" is redundant and could be simplified.
-Search contexts are defined in the `context` object inside of a [declarative config](/self-hosting/more/declarative-config). Repositories can be included / excluded from a search context by specifying the repo's URL in either the `include` array or `exclude` array. Glob patterns are supported. +Search contexts are defined in the `context` object inside a [declarative config](/self-hosting/more/declarative-config). Repositories can be included / excluded from a search context by specifying the repo's URL in either the `include` array or `exclude` array. Glob patterns are supported.🧰 Tools
🪛 LanguageTool
[style] ~17-~17: This phrase is redundant. Consider using “inside”.
Context: ...xts are defined in thecontext
object inside of a [declarative config](/self-hosting/mo...(OUTSIDE_OF)
48-85
: Note about JSON comments in the configuration example.The example configuration contains JavaScript-style comments, but standard JSON doesn't support comments. Since this is documentation for users, it should be clarified that these comments are for documentation purposes only and wouldn't be valid in an actual JSON file.
Add a note before the JSON example:
+> Note: The comments in the example below are for documentation purposes only. Standard JSON does not support comments, so they should be removed in your actual configuration file. + ```json { "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json",schemas/v3/index.json (1)
72-77
: Strengthen validation for theinclude
arrayA search context without any repository patterns is probably a configuration mistake, yet the schema permits an empty array.
Consider enforcing at least one entry and uniqueness:"include": { "type": "array", "description": "...", "items": { "type": "string" }, + "minItems": 1, + "uniqueItems": true, "examples": [You may want the same
uniqueItems
guard onexclude
.packages/web/src/ee/features/searchContexts/syncSearchContexts.ts (1)
21-42
: Consider adding pagination for repository fetching.The current implementation fetches all repositories at once, which could lead to performance issues with large repository sets. Consider implementing pagination if the organization might have a large number of repositories.
- const allRepos = await prisma.repo.findMany({ + // Fetch repositories in batches to handle large repository sets + const batchSize = 100; + let skip = 0; + let allRepos: { id: number; name: string }[] = []; + + while (true) { + const batch = await prisma.repo.findMany({ where: { orgId: SINGLE_TENANT_ORG_ID, }, select: { id: true, name: true, }, + take: batchSize, + skip: skip } - }); + ); + + if (batch.length === 0) break; + + allRepos = [...allRepos, ...batch]; + skip += batchSize; + + if (batch.length < batchSize) break; + }packages/web/src/app/[domain]/settings/billing/page.tsx (1)
1-108
: Consider implementing error boundary for improved error handling.While the current error handling approach works, consider implementing a React Error Boundary component to catch and handle errors more gracefully at the UI level.
// Example implementation in a separate ErrorBoundary component import { ErrorBoundary } from "@/components/errorBoundary"; // In the parent component that renders BillingPage <ErrorBoundary fallback={<BillingErrorState />} > <BillingPage params={{ domain }} /> </ErrorBoundary>packages/web/src/actions.ts (1)
1134-1148
: Minor: parenthesis readability makeswithAuth
’strue
flag easy to mis-placeThe current multiline layout obscures that
true
is the second argument towithAuth
. A tiny refactor makes the intent obvious:-export const getSearchContexts = async (domain: string) => sew(() => - withAuth((session) => - withOrgMembership(session, domain, async ({ orgId }) => { +export const getSearchContexts = async (domain: string) => sew(() => + withAuth( + (session) => withOrgMembership(session, domain, async ({ orgId }) => { const searchContexts = await prisma.searchContext.findMany({ where: { orgId } }); return searchContexts.map(({ name, description }) => ({ name, description: description ?? undefined })); - } - ), /* allowSingleTenantUnauthedAccess = */ true)); + }), + /* allowSingleTenantUnauthedAccess = */ true, + ));No functional change – just avoids future mis-parenthesising.
packages/web/src/ee/features/billing/actions.ts (5)
3-6
: Consolidate duplicated imports from@/actions
.The file imports
@/actions
twice—once forgetMe, sew, withAuth
and again forwithOrgMembership
. This incurs an unnecessary module resolution, slightly affects bundle size, and can drift out-of-sync if one list is updated but the other isn’t.-import { getMe, sew, withAuth } from "@/actions"; -import { withOrgMembership } from "@/actions"; +import { getMe, sew, withAuth, withOrgMembership } from "@/actions";
77-80
: Cache or configure the Stripe Price ID instead of listing prices on every request.
stripeClient.prices.list
is performed on each subscription/checkout call.
Listing can add 200–300 ms latency per request and is rate-limited by Stripe. Since your product/price are static, prefer:
- Store the Price ID in an env var (
STRIPE_PRICE_ID
) and reference it directly, or- Cache the first call result in a module-level variable (the module is hot-reused in serverless).
-const prices = await stripeClient.prices.list({ product: env.STRIPE_PRODUCT_ID, expand: ['data.product'] }); -const priceId = prices.data[0].id; +const priceId = + env.STRIPE_PRICE_ID + ?? (await getCachedPriceId(stripeClient, env.STRIPE_PRODUCT_ID));(You would implement
getCachedPriceId
to memoise the lookup.)Also applies to: 149-152
235-260
: Validate the new billing email before sending it to Stripe.
changeSubscriptionBillingEmail
forwardsnewEmail
directly to Stripe without syntax or reasonableness checks. A malformed address will be accepted by Stripe’s API but later cause invoice-delivery failures.Consider:
import isEmail from "validator/lib/isEmail"; if (!isEmail(newEmail)) { return { statusCode: StatusCodes.BAD_REQUEST, errorCode: ErrorCode.INVALID_EMAIL, message: "Provided email is not valid", } satisfies ServiceError; }
16-118
: Race-condition warning on trial subscription creation.Between the existence check (
getSubscriptionForOrg
) and the subsequentstripeClient.subscriptions.create
, another request could slip in and create a subscription, leading to duplicate subs and reconciliation headaches.Consider wrapping the creation in a DB transaction with a pessimistic lock on the org row, or using a unique constraint on
orgId
inside asubscription
table and catching the unique-violation error.
1-280
: Add explicit return types for exported server actions.TypeScript infers the unions of success objects and
ServiceError
, but explicit signatures improve IDE DX and guard against accidental structural changes.Example:
export const getSubscriptionInfo = async ( domain: string ): Promise<{ status: string; plan: string; seats: number; perSeatPrice: number; nextBillingDate: number; } | ServiceError> => sew(() => …
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
docs/images/search_contexts_example.png
is excluded by!**/*.png
yarn.lock
is excluded by!**/yarn.lock
,!**/*.lock
📒 Files selected for processing (61)
CHANGELOG.md
(1 hunks)LICENSE
(1 hunks)Makefile
(1 hunks)docs/docs.json
(3 hunks)docs/docs/more/syntax-reference.mdx
(1 hunks)docs/self-hosting/license-key.mdx
(1 hunks)docs/self-hosting/more/declarative-config.mdx
(1 hunks)docs/self-hosting/more/search-contexts.mdx
(1 hunks)ee/LICENSE
(1 hunks)package.json
(1 hunks)packages/db/prisma/migrations/20250403044104_add_search_contexts/migration.sql
(1 hunks)packages/db/prisma/schema.prisma
(2 hunks)packages/schemas/src/v3/index.schema.ts
(2 hunks)packages/schemas/src/v3/index.type.ts
(2 hunks)packages/web/package.json
(2 hunks)packages/web/src/actions.ts
(6 hunks)packages/web/src/app/[domain]/components/navigationMenu.tsx
(2 hunks)packages/web/src/app/[domain]/components/searchBar/constants.ts
(2 hunks)packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx
(6 hunks)packages/web/src/app/[domain]/components/searchBar/useRefineModeSuggestions.ts
(1 hunks)packages/web/src/app/[domain]/components/searchBar/useSuggestionModeAndQuery.ts
(2 hunks)packages/web/src/app/[domain]/components/searchBar/useSuggestionModeMappings.ts
(1 hunks)packages/web/src/app/[domain]/components/searchBar/useSuggestionsData.ts
(6 hunks)packages/web/src/app/[domain]/components/searchBar/zoektLanguageExtension.ts
(1 hunks)packages/web/src/app/[domain]/layout.tsx
(2 hunks)packages/web/src/app/[domain]/onboard/page.tsx
(1 hunks)packages/web/src/app/[domain]/search/page.tsx
(3 hunks)packages/web/src/app/[domain]/settings/billing/page.tsx
(2 hunks)packages/web/src/app/[domain]/settings/layout.tsx
(1 hunks)packages/web/src/app/[domain]/settings/members/page.tsx
(1 hunks)packages/web/src/app/[domain]/upgrade/page.tsx
(1 hunks)packages/web/src/app/api/(client)/client.ts
(2 hunks)packages/web/src/app/api/(server)/stripe/route.ts
(1 hunks)packages/web/src/app/components/securityCard.tsx
(2 hunks)packages/web/src/app/error.tsx
(2 hunks)packages/web/src/app/layout.tsx
(2 hunks)packages/web/src/app/login/verify/page.tsx
(2 hunks)packages/web/src/app/login/verify/verificationFailed.tsx
(2 hunks)packages/web/src/app/onboard/components/onboardHeader.tsx
(1 hunks)packages/web/src/ee/features/billing/actions.ts
(1 hunks)packages/web/src/ee/features/billing/components/changeBillingEmailCard.tsx
(1 hunks)packages/web/src/ee/features/billing/components/checkout.tsx
(1 hunks)packages/web/src/ee/features/billing/components/enterpriseUpgradeCard.tsx
(2 hunks)packages/web/src/ee/features/billing/components/manageSubscriptionButton.tsx
(1 hunks)packages/web/src/ee/features/billing/components/teamUpgradeCard.tsx
(1 hunks)packages/web/src/ee/features/billing/serverUtils.ts
(1 hunks)packages/web/src/ee/features/billing/stripe.ts
(1 hunks)packages/web/src/ee/features/searchContexts/syncSearchContexts.ts
(1 hunks)packages/web/src/env.mjs
(1 hunks)packages/web/src/features/entitlements/README.md
(1 hunks)packages/web/src/features/entitlements/constants.ts
(1 hunks)packages/web/src/features/entitlements/planProvider.tsx
(1 hunks)packages/web/src/features/entitlements/server.ts
(1 hunks)packages/web/src/features/entitlements/useHasEntitlement.ts
(1 hunks)packages/web/src/features/entitlements/usePlan.ts
(1 hunks)packages/web/src/initialize.ts
(4 hunks)packages/web/src/lib/constants.ts
(1 hunks)packages/web/src/lib/errorCodes.ts
(1 hunks)packages/web/src/lib/schemas.ts
(1 hunks)packages/web/src/lib/server/searchService.ts
(2 hunks)schemas/v3/index.json
(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (18)
packages/web/src/app/login/verify/page.tsx (1)
packages/web/src/lib/constants.ts (1)
SOURCEBOT_SUPPORT_EMAIL
(33-33)
packages/web/src/app/[domain]/layout.tsx (1)
packages/web/src/ee/features/billing/actions.ts (1)
getSubscriptionInfo
(262-279)
packages/web/src/features/entitlements/usePlan.ts (1)
packages/web/src/features/entitlements/planProvider.tsx (1)
PlanContext
(6-6)
packages/web/src/app/login/verify/verificationFailed.tsx (1)
packages/web/src/lib/constants.ts (1)
SOURCEBOT_SUPPORT_EMAIL
(33-33)
packages/web/src/app/components/securityCard.tsx (1)
packages/web/src/lib/constants.ts (1)
SOURCEBOT_SUPPORT_EMAIL
(33-33)
packages/web/src/app/error.tsx (1)
packages/web/src/lib/constants.ts (1)
SOURCEBOT_SUPPORT_EMAIL
(33-33)
packages/web/src/app/[domain]/components/searchBar/useSuggestionModeAndQuery.ts (1)
packages/web/src/app/[domain]/components/searchBar/useSuggestionModeMappings.ts (1)
useSuggestionModeMappings
(22-104)
packages/web/src/app/api/(client)/client.ts (4)
packages/web/src/lib/server/searchService.ts (1)
search
(87-146)packages/web/src/lib/types.ts (2)
SearchRequest
(7-7)SearchResponse
(8-8)packages/web/src/lib/serviceError.ts (1)
ServiceError
(11-11)packages/web/src/lib/utils.ts (1)
isServiceError
(151-157)
packages/web/src/features/entitlements/planProvider.tsx (1)
packages/web/src/features/entitlements/constants.ts (1)
Plan
(7-7)
packages/web/src/features/entitlements/useHasEntitlement.ts (2)
packages/web/src/features/entitlements/constants.ts (2)
Entitlement
(14-14)entitlementsByPlan
(16-20)packages/web/src/features/entitlements/usePlan.ts (1)
usePlan
(4-7)
packages/web/src/ee/features/billing/components/enterpriseUpgradeCard.tsx (1)
packages/web/src/lib/constants.ts (1)
SOURCEBOT_SUPPORT_EMAIL
(33-33)
packages/web/src/app/[domain]/components/searchBar/useRefineModeSuggestions.ts (2)
packages/web/src/features/entitlements/useHasEntitlement.ts (1)
useHasEntitlement
(6-10)packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx (1)
Suggestion
(22-27)
packages/web/src/app/[domain]/search/page.tsx (3)
packages/web/src/components/hooks/use-toast.ts (2)
useToast
(194-194)toast
(194-194)packages/web/src/lib/utils.ts (1)
unwrapServiceError
(243-250)packages/web/src/app/api/(client)/client.ts (1)
search
(8-23)
packages/web/src/app/[domain]/settings/billing/page.tsx (1)
packages/web/src/ee/features/billing/actions.ts (1)
getSubscriptionInfo
(262-279)
packages/web/src/initialize.ts (3)
packages/schemas/src/v3/index.type.ts (2)
ConnectionConfig
(7-11)SourcebotConfig
(13-28)packages/web/src/lib/constants.ts (1)
SINGLE_TENANT_ORG_ID
(29-29)packages/web/src/ee/features/searchContexts/syncSearchContexts.ts (1)
syncSearchContexts
(8-111)
packages/web/src/features/entitlements/server.ts (4)
packages/web/src/lib/utils.ts (1)
base64Decode
(160-163)packages/web/src/features/entitlements/constants.ts (3)
Plan
(7-7)Entitlement
(14-14)entitlementsByPlan
(16-20)packages/backend/src/env.ts (1)
env
(22-52)packages/web/src/lib/constants.ts (1)
SOURCEBOT_SUPPORT_EMAIL
(33-33)
packages/web/src/actions.ts (2)
packages/web/src/ee/features/billing/serverUtils.ts (3)
getSubscriptionForOrg
(53-80)incrementOrgSeatCount
(9-29)decrementOrgSeatCount
(31-51)packages/web/src/lib/utils.ts (1)
isServiceError
(151-157)
packages/web/src/ee/features/billing/serverUtils.ts (3)
packages/web/src/ee/features/billing/stripe.ts (1)
stripeClient
(8-11)packages/web/src/lib/serviceError.ts (4)
stripeClientNotInitialized
(123-129)ServiceError
(11-11)notFound
(91-97)orgInvalidSubscription
(107-113)packages/web/src/lib/utils.ts (1)
isServiceError
(151-157)
🪛 LanguageTool
packages/web/src/features/entitlements/README.md
[uncategorized] ~7-~7: Loose punctuation mark.
Context: ...ce** level. Some definitions: - Plan
: A plan is a tier of features. Examples:...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~8-~8: Loose punctuation mark.
Context: ...self-hosted:enterprise. -
Entitlement`: An entitlement is a feature that is ava...
(UNLIKELY_OPENING_PUNCTUATION)
[misspelling] ~8-~8: Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.
Context: ...ement is a feature that is available to a instance. Examples: search-contexts
, ...
(EN_A_VS_AN)
docs/self-hosting/more/search-contexts.mdx
[style] ~17-~17: This phrase is redundant. Consider using “inside”.
Context: ...xts are defined in the context
object inside of a [declarative config](/self-hosting/mo...
(OUTSIDE_OF)
docs/docs/more/syntax-reference.mdx
[uncategorized] ~5-~5: This verb may not be in the correct tense. Consider changing the tense to fit the context better.
Context: ...owerful regex-based query language that enabled precise code search within large codeba...
(AI_EN_LECTOR_REPLACEMENT_VERB_TENSE)
[uncategorized] ~30-~30: Did you mean: “By default,”?
Context: ...ts from filepaths that match the regex. By default all files are searched. | file:README
...
(BY_DEFAULT_COMMA)
[uncategorized] ~30-~30: A determiner appears to be missing. Consider inserting it.
Context: ...r results to filepaths that match regex /README/
file:"my file"
- Filter results to filepaths that ma...
(AI_EN_LECTOR_MISSING_DETERMINER)
[uncategorized] ~31-~31: Did you mean: “By default,”?
Context: ...esults from repos that match the regex. By default all repos are searched. | repo:linux
...
(BY_DEFAULT_COMMA)
[uncategorized] ~32-~32: Did you mean: “By default,”?
Context: ... results from a specific branch or tag. By default only the default branch is searched...
(BY_DEFAULT_COMMA)
[uncategorized] ~33-~33: Did you mean: “By default,”?
Context: ...blob/main/lib/linguist/languages.yml)). By default all languages are searched. | `lang:Typ...
(BY_DEFAULT_COMMA)
🪛 Biome (1.9.4)
packages/web/src/features/entitlements/server.ts
[error] 27-27: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (93)
packages/web/src/lib/constants.ts (1)
33-33
: Centralize support email
IntroducingSOURCEBOT_SUPPORT_EMAIL
replaces hardcoded addresses and ensures consistency across the UI. Please verify that all components reference this constant and remove any remaining hardcoded email strings.Makefile (1)
36-36
: Reset Prisma migrations insoft-reset
target
Addingyarn dev:prisma:migrate:reset
ensures the database schema is correctly reset after clearing data. Verify that thedev:prisma:migrate:reset
script exists inpackage.json
and that it performs as intended.packages/web/src/app/api/(server)/stripe/route.ts (1)
6-6
: Refactor billing import path
ThestripeClient
import now points to the EE billing module, aligning with the billing feature refactor. Ensure the exportedstripeClient
in@/ee/features/billing/stripe
initializes correctly with the proper API keys and that no residual imports of the old path remain.packages/web/src/app/onboard/components/onboardHeader.tsx (1)
3-3
: Update import to new billing module path.The
IS_BILLING_ENABLED
flag import has been correctly updated to reference the enterprise edition billing module (@/ee/features/billing/stripe
). This aligns with the recent billing feature refactor. No further changes needed.packages/web/src/ee/features/billing/components/changeBillingEmailCard.tsx (1)
8-8
: Import billing action from EE feature directory.The
changeSubscriptionBillingEmail
function import has been updated to the enterprise edition billing actions module (@/ee/features/billing/actions
). This centralizes billing logic as intended. Looks good.packages/web/src/app/[domain]/settings/members/page.tsx (1)
10-10
: Align billing flag import with EE billing module.The
IS_BILLING_ENABLED
import was correctly updated to pull from@/ee/features/billing/stripe
, matching other components. No additional adjustments are required.packages/web/src/lib/schemas.ts (1)
5-5
: No-op formatting change.A single blank line was added after the import statement. There are no functional or logical changes in this segment.
packages/web/src/ee/features/billing/components/manageSubscriptionButton.tsx (1)
11-11
: Import path refactoring looks goodThe updated import path for
getCustomerPortalSessionLink
properly aligns with the restructuring of billing functionality into the dedicated Enterprise Edition module. This change supports the PR objective of organizing billing-related code under the commercial license.packages/web/src/ee/features/billing/components/teamUpgradeCard.tsx (1)
11-11
: Relative import path is appropriateThe change from an absolute import to a relative import for
createStripeCheckoutSession
is consistent with the billing code restructuring. Both the component and the imported actions now reside within the same billing feature module, making this relative path a logical choice.packages/web/src/app/[domain]/settings/layout.tsx (1)
5-5
: Import path properly updated for billing featureThe updated import path for
IS_BILLING_ENABLED
correctly reflects the movement of billing-related functionality to the Enterprise Edition module. This maintains consistency with the overall restructuring of billing features under the commercial license.packages/web/src/lib/errorCodes.ts (1)
25-25
: New error code supports search contexts featureThe addition of the
SEARCH_CONTEXT_NOT_FOUND
error code is appropriate for the new search contexts feature. This error code follows the established naming pattern and will be useful for handling cases where a user tries to search using a non-existent context.docs/self-hosting/more/declarative-config.mdx (1)
6-8
: Well-placed warning about multi-tenancy limitations.The warning clearly informs users about a limitation of declarative configuration with multi-tenancy mode. This is an important clarification that helps users understand the constraints of the feature.
packages/web/src/app/login/verify/verificationFailed.tsx (1)
7-7
: Good refactoring to use a centralized support email constant.Centralizing the support email address in
constants.ts
improves maintainability. If the support email changes in the future, it can be updated in a single location.Also applies to: 38-38
packages/web/src/app/error.tsx (1)
12-12
: Good refactoring to use a centralized support email constant.This change ensures consistency across the application by using the centralized
SOURCEBOT_SUPPORT_EMAIL
constant instead of hardcoding the email address. This makes future maintenance easier.Also applies to: 80-80
CHANGELOG.md (1)
8-12
: Good documentation of the new search contexts feature.The changelog entry appropriately documents the addition of search contexts as a new enterprise feature, with a clear description of what the feature does and a link to the related PR.
packages/web/src/app/[domain]/components/searchBar/zoektLanguageExtension.ts (1)
50-50
: Correctly updated tokenizer to recognize the new context prefix.The change properly adds the
context:
prefix to the regular expression that identifies keywords in the search query language. This ensures syntax highlighting works correctly with the new search contexts feature.packages/web/src/app/components/securityCard.tsx (2)
6-6
: Good practice: Centralizing constants.Adding the import for
SOURCEBOT_SUPPORT_EMAIL
from a central constants file is a good practice for maintainability.
66-66
: Consistent usage of support email constant.Replacing the hardcoded email address with the centralized constant improves maintainability. If the support email needs to change in the future, it can be updated in a single location.
packages/web/package.json (2)
116-116
: Appropriate dependency for glob pattern matching.Adding the
micromatch
library is suitable for implementing repository filtering with glob patterns in search contexts.
141-141
: Type definitions for micromatch.Including the TypeScript type definitions for
micromatch
ensures proper type checking and IDE support.packages/web/src/ee/features/billing/components/enterpriseUpgradeCard.tsx (2)
3-3
: Good practice: Centralizing constants.Adding the import for
SOURCEBOT_SUPPORT_EMAIL
is consistent with the pattern applied in other components.
17-17
: Consistent usage of support email constant while preserving subject.Replacing the hardcoded email address with the centralized constant while maintaining the email subject is a good refactoring. This ensures consistent contact information across the application.
packages/web/src/app/login/verify/page.tsx (1)
16-16
: Good: Using centralized constants for support emailThe change improves maintainability by replacing the hardcoded email address with a centralized constant from
@/lib/constants
. This ensures consistency across the application and makes future updates easier.Also applies to: 93-93
packages/web/src/features/entitlements/usePlan.ts (1)
1-7
: Well-implemented React hook following best practicesThis custom hook follows React best practices for context consumption and provides a clean API for components to access the current plan. The hook is concise and has a single responsibility, making it easy to understand and test.
packages/web/src/app/[domain]/onboard/page.tsx (1)
8-8
: Good refactoring of billing import pathsThe updated import paths correctly reflect the architectural change of moving billing-related code under the enterprise edition (
ee
) directory structure. This aligns with the goal of separating open-source and commercial features.Also applies to: 10-10
packages/web/src/app/[domain]/layout.tsx (1)
13-13
: Refactored billing code to EE moduleThe changes have correctly relocated billing-related code to the Enterprise Edition module. The
getSubscriptionInfo
function replacesfetchSubscription
with equivalent functionality but proper organization within the EE feature structure.Also applies to: 16-16, 62-62
packages/web/src/app/layout.tsx (1)
10-11
: Proper integration of the plan provider systemThe addition of
PlanProvider
at the root layout level effectively enables plan-based feature gating throughout the application. The component is correctly positioned in the provider tree to make plan information available to all child components.Also applies to: 32-47
packages/web/src/ee/features/billing/stripe.ts (1)
4-4
: Successfully gated billing behind entitlementsThe implementation now correctly gates billing features behind both the presence of a Stripe secret key AND the 'billing' entitlement. This aligns with the enterprise feature strategy described in the PR objectives.
Also applies to: 6-6
packages/web/src/features/entitlements/useHasEntitlement.ts (1)
1-10
: Well-structured hook for feature entitlement checksThis hook is cleanly implemented and follows React best practices. It effectively checks if a user's current plan includes a specific entitlement by:
- Getting the current plan via the
usePlan
hook- Looking up available entitlements for that plan
- Checking if the requested entitlement is included
This implementation aligns with the enterprise feature gating described in the PR.
LICENSE (1)
1-7
: License update properly reflects the dual-licensing modelThis license update clearly establishes the dual-licensing model for the project:
- Enterprise code in "ee/" and "packages/web/src/ee/" directories is under the enterprise license
- Third-party components retain their original licenses
- All other content remains under the MIT license
This aligns with the PR objectives of introducing enterprise features while maintaining an open-core model.
packages/web/src/app/[domain]/components/navigationMenu.tsx (2)
14-16
: Updated imports align with relocated billing functionalityThese import changes correctly reference the relocated billing-related code that has been moved to the enterprise edition directory structure.
28-28
: Updated subscription retrieval logic using the new functionThe subscription retrieval logic has been properly updated to use the new
getSubscriptionInfo
function from the enterprise edition directory, while maintaining the same conditional behavior based on billing enablement.packages/web/src/features/entitlements/planProvider.tsx (1)
1-21
: Well-implemented context provider for plan-based feature gatingThe
PlanContext
andPlanProvider
provide a clean implementation for sharing the current plan throughout the application. This is essential for the entitlements system to gate enterprise features like search contexts.The implementation follows React best practices for context providers and consumers.
packages/web/src/app/[domain]/components/searchBar/useSuggestionModeAndQuery.ts (2)
5-5
: Updated import to use dynamic suggestion mappingsThe code now imports the
useSuggestionModeMappings
hook instead of using static mappings, which will enable entitlement-based suggestion modes.
21-22
: Dynamic suggestion mappings based on user entitlementsThe suggestion mode mappings are now obtained from the
useSuggestionModeMappings
hook which dynamically includes the "context" suggestion mode based on user entitlements. This properly gates the search contexts feature behind entitlements.- const suggestionModeMappings = ... + const suggestionModeMappings = useSuggestionModeMappings();packages/web/src/app/[domain]/search/page.tsx (4)
13-13
: Good addition of utility imports for error handlingAdded imports for
unwrapServiceError
anduseToast
to support the new error handling functionality.Also applies to: 25-25
48-48
: Destructuring toast from useToast hookProperly added toast functionality to display error messages.
50-63
: Enhanced error handling in search queryThe query function now properly handles service errors by:
- Using
unwrapServiceError
to throw errors instead of returning them- Disabling automatic retries with
retry: false
to prevent repeating failed searches- Capturing the error object for use in notifications
This improves error handling for the new search contexts feature.
65-71
: Added user-friendly error notificationsAdded an effect to display toast notifications when search queries fail, providing clear feedback to users. This is especially important for enterprise features like search contexts that might return specific errors.
packages/web/src/app/api/(client)/client.ts (3)
4-6
: Added necessary imports for error handlingAdded imports for the
ServiceError
type and theisServiceError
utility function to support the error handling changes.
8-8
: Updated return type to handle service errorsThe function signature now correctly indicates that it can return either a
SearchResponse
or aServiceError
, making the error handling more explicit and type-safe.
18-20
: Added explicit handling of service errorsThe function now checks if the result is a
ServiceError
before attempting to parse it, preventing potential runtime errors when service errors occur. This is particularly important for features like search contexts that might return specific error types.docs/docs.json (3)
42-42
: Added syntax reference documentationAdded link to new syntax reference documentation, helping users understand the query language capabilities including the new search contexts feature.
56-57
: Added license key documentationAdded documentation for license key activation, which is essential for users who want to use Enterprise Edition features like search contexts.
66-67
: Added search contexts documentationAdded dedicated documentation for the new search contexts feature, ensuring users can understand how to configure and use this Enterprise Edition capability.
packages/web/src/app/[domain]/components/searchBar/useRefineModeSuggestions.ts (5)
1-7
: Clean imports and client directive setup.The imports are well-organized and the client directive is correctly placed at the top of the file. The inclusion of the
useHasEntitlement
hook will be used to conditionally render the search contexts feature based on user entitlements.
8-10
: Simple helper function for negating search prefixes.This utility function provides a clean way to generate negated search prefixes, promoting code reuse throughout the component.
12-14
: Feature flag check for search contexts.Good use of the entitlement system to conditionally enable the search contexts feature based on user plan.
15-28
: Conditional rendering of search context suggestions.The implementation correctly uses the feature flag to conditionally include search context suggestions in the returned array. The spread operator with a conditional array is a clean pattern for this use case.
97-101
: Properly memoized suggestions with correct dependency.The
useMemo
dependency array correctly includesisSearchContextsEnabled
, ensuring the suggestions are recalculated if the entitlement status changes.packages/web/src/app/[domain]/upgrade/page.tsx (3)
4-5
: Updated import paths for billing components.The imports have been updated from relative to absolute paths, which is consistent with the PR objective of moving billing-related code to the enterprise edition.
12-13
: Updated import paths for billing utilities.These imports have been updated to reflect the new location of billing-related code in the enterprise edition, consistent with the PR objectives.
20-20
: Updated function call to enterprise billing action.The function call has been updated to use the new enterprise-specific billing action.
packages/web/src/features/entitlements/constants.ts (3)
2-7
: Well-defined plan types and labels.The plan labels are clearly defined with descriptive names for each plan type. The use of
as const
ensures type safety by preserving the literal types.
10-14
: Clear definition of available entitlements.The entitlements are defined as a constant array with descriptive names. The TypeScript type definition using indexed access types ensures type safety for entitlement references throughout the codebase.
16-20
: Logical entitlement mapping by plan.The entitlements are logically mapped to each plan type:
- OSS plan has no premium features
- Cloud team plan includes billing features
- Self-hosted enterprise plan includes search contexts
This aligns with the PR objective of introducing search contexts as an enterprise feature.
packages/web/src/app/[domain]/components/searchBar/useSuggestionsData.ts (7)
6-6
: Added import for search contexts data fetching.The import for
getSearchContexts
is correctly added to support the new search contexts feature.
22-22
: Updated utility imports.The import now explicitly includes
isServiceError
which is used for error handling in the queries.
60-63
: Improved error handling for file suggestions.Added proper error handling for file suggestions query to gracefully handle service errors.
79-82
: Improved error handling for symbol suggestions.Added proper error handling for symbol suggestions query to gracefully handle service errors.
101-117
: Well-implemented search contexts suggestion fetching.The implementation of search context suggestions follows the established pattern in the file:
- Uses useQuery with appropriate query key
- Provides error handling for service errors
- Transforms fetched data into the expected suggestion format
- Only enabled when the suggestion mode is "context"
- Properly tracks loading state
This ensures consistent behavior with other suggestion types.
146-147
: Updated loading state to include search contexts.The loading state is correctly updated to include the search contexts loading state, ensuring the UI properly shows loading indicators when fetching context suggestions.
153-153
: Added search contexts to returned suggestions.The return object now includes the search context suggestions, making them available to the component that uses this hook.
packages/db/prisma/schema.prisma (2)
69-80
: Well-designed search context schema modelThe new
SearchContext
model is well-structured with appropriate fields and relationships. The unique constraint on[name, orgId]
ensures that context names are unique within an organization.
64-64
: Appropriate bidirectional relationshipsThe bidirectional relationships between
SearchContext
and bothRepo
andOrg
models are correctly established, enabling efficient querying in both directions.Also applies to: 157-157
packages/schemas/src/v3/index.type.ts (2)
16-21
: Good implementation of contexts configurationThe
contexts
property is properly documented as an Enterprise Edition feature with a link to the documentation. The dictionary pattern with string keys mapping toSearchContext
objects is appropriate for configuration flexibility.
81-103
: Well-defined SearchContext interfaceThe
SearchContext
interface has clear, requiredinclude
and optionalexclude
arrays for repository patterns, with good documentation that explains the expected format without protocol prefixes and support for glob patterns.packages/web/src/app/[domain]/components/searchBar/useSuggestionModeMappings.ts (2)
22-104
: Great implementation of feature-gated suggestion mappingsThe
useSuggestionModeMappings
hook properly utilizesuseMemo
for performance optimization and implements feature-gating through theuseHasEntitlement
hook. The conditional inclusion of search context mappings ensures the UI only shows available features.
91-99
: Correct TypeScript pattern for conditional inclusionThe use of the spread operator with a conditional array and the
satisfies
operator ensures type safety while conditionally including the search contexts feature when entitled.docs/docs/more/syntax-reference.mdx (1)
34-35
: Excellent documentation of the new context prefixThe documentation for the
context:
prefix is clear and concise, with helpful examples showing both positive and negative filtering. The link to the detailed documentation is appropriate.packages/web/src/features/entitlements/server.ts (3)
1-5
: LGTM! Imports are appropriate for the license/entitlement system.The imports bring in all necessary dependencies including environment variables, type definitions, utilities for decoding, validation schema support, and constants for error messaging.
9-13
: Well-structured schema definition for license key validation.The schema properly defines the required fields (
id
) and optional fields (expiryDate
) with appropriate validation (datetime format for expiry). This provides a solid foundation for license key validation.
49-53
: LGTM! Entitlement check logic is clear and concise.The function correctly obtains the current plan and checks if the requested entitlement is included in the plan's entitlements.
docs/self-hosting/more/search-contexts.mdx (4)
1-9
: Well-structured enterprise feature documentation with clear license note.The documentation properly identifies this as an Enterprise Edition feature and links to license key information, making it clear to users that this functionality requires enterprise licensing.
10-15
: Great examples demonstrating search context usage.The examples provide clear, practical use cases showing how to utilize search contexts in queries, including combined contexts with logical operators. This helps users understand the feature's capabilities.
87-92
: Helpful accordion explanation of repository URL format.The accordion section clearly explains how repository URLs should be formatted, with good examples for different Git hosts. This prevents potential user confusion about URL formatting.
102-106
: Good explanation of advanced query options.The documentation nicely explains how to combine or negate contexts in search queries and provides a link to more detailed syntax information. This helps users leverage the feature's full capabilities.
packages/web/src/app/[domain]/components/searchBar/constants.ts (1)
7-23
: Clean addition of the new context search prefix.The
context
prefix has been correctly added to theSearchPrefix
enum, enabling search context functionality in the search bar. This aligns with the documentation and other parts of the implementation.packages/schemas/src/v3/index.schema.ts (2)
69-108
: Well-defined schema for theSearchContext
type.The schema properly defines:
- Required fields (
include
) for repositories to include in the context- Optional fields (
exclude
,description
) with clear descriptions- Appropriate property types and good examples
The schema aligns perfectly with the documentation and provides a strong foundation for validating search context configurations.
117-126
: Well-structured top-level contexts property in the schema.The contexts property is:
- Properly marked as a Sourcebot EE feature
- Limited to valid context names via regex pattern
- References the
SearchContext
definition- Includes appropriate documentation link
This integration enables the search contexts feature while maintaining schema validation.
packages/web/src/ee/features/searchContexts/syncSearchContexts.ts (2)
8-19
: Well-implemented entitlement check and error handling.The function correctly validates the environment and entitlement requirements before proceeding with synchronization. The error message is detailed and includes helpful information about the required plan and support contact.
56-90
: 🛠️ Refactor suggestionConsider wrapping operations in a transaction.
The database operations aren't wrapped in a transaction, which could lead to an inconsistent state if an error occurs mid-operation. Wrapping related operations in a transaction would ensure atomicity.
+ // Wrap in a transaction for atomicity + await prisma.$transaction(async (tx) => { - await prisma.searchContext.upsert({ + await tx.searchContext.upsert({ where: { name_orgId: { name: key, orgId: SINGLE_TENANT_ORG_ID, } }, // ... rest of the upsert operation }); + });Likely an incorrect or invalid review comment.
packages/web/src/app/[domain]/settings/billing/page.tsx (2)
3-6
: Clean import refactoring to use enterprise edition features.The imports have been updated to correctly reference the billing components and actions from the enterprise edition directory structure.
31-31
: Function update aligns with the new billing architecture.The change from
getSubscriptionData
togetSubscriptionInfo
maintains the same interface and functionality while using the refactored billing implementation.packages/db/prisma/migrations/20250403044104_add_search_contexts/migration.sql (4)
1-9
: Well-structured SearchContext table creation.The table structure is clean with appropriate column types and constraints. The primary key is properly defined.
11-17
: Good implementation of the many-to-many relationship join table.The join table
_RepoToSearchContext
correctly implements a many-to-many relationship with a composite primary key.
19-23
: Appropriate indexing for performance.The unique index on
(name, orgId)
ensures that context names are unique within an organization, and the index on the join table will improve query performance.
25-32
: Correct foreign key constraints with appropriate cascade behavior.The foreign key constraints are well-defined with CASCADE for both DELETE and UPDATE operations, ensuring referential integrity as organizations or repositories are modified or removed.
packages/web/src/lib/server/searchService.ts (4)
32-32
: Good addition of reposet to zoektPrefixes enum.Adding the reposet prefix to the enum ensures consistency with other prefixes and maintains the documentation of supported prefixes.
35-85
: Well-implemented query transformation with good error handling.The
transformZoektQuery
function logically handles different query prefixes and provides good error handling when a search context isn't found. The transformation ofcontext:
intoreposet:
is a clean implementation.However, consider adding caching for context lookups to improve performance with repeated queries:
+ // Add a simple in-memory cache with TTL + const contextCache = new Map<string, { repos: string[], timestamp: number }>(); + const CACHE_TTL_MS = 60 * 1000; // 1 minute cache const transformZoektQuery = async (query: string, orgId: number): Promise<string | ServiceError> => { // ... // Inside the context: handling section else if (part.match(/^-?context:.+$/)) { const isNegated = part.startsWith("-"); const contextName = part.slice(part.indexOf(":") + 1); + // Check cache first + const cacheKey = `${orgId}:${contextName}`; + const cachedContext = contextCache.get(cacheKey); + + if (cachedContext && (Date.now() - cachedContext.timestamp) < CACHE_TTL_MS) { + newQueryParts.push(`${isNegated ? "-" : ""}${zoektPrefixes.reposet}${cachedContext.repos.join(",")}`); + continue; + } const context = await prisma.searchContext.findUnique({ // ... }); // If the context doesn't exist, return an error. if (!context) { return { errorCode: ErrorCode.SEARCH_CONTEXT_NOT_FOUND, message: `Search context "${contextName}" not found`, statusCode: StatusCodes.NOT_FOUND, } satisfies ServiceError; } const names = context.repos.map((repo) => repo.name); + // Update cache + contextCache.set(cacheKey, { repos: names, timestamp: Date.now() }); newQueryParts.push(`${isNegated ? "-" : ""}${zoektPrefixes.reposet}${names.join(",")}`); }
87-92
: Good integration of query transformation in the search function.The search function now correctly integrates the transformation and handles any errors before proceeding with the search. The previous functionality is preserved while adding the new capabilities.
35-85
:❓ Verification inconclusive
Add handling for nested query structures.
The current implementation splits queries on spaces, which won't correctly handle parenthesized expressions or quoted strings. Consider using a more robust parsing approach for complex queries.
🏁 Script executed:
#!/bin/bash # Verify if there are any nested or parenthesized queries using context: in codebase examples # Look for examples of complex context: queries with parentheses or quotes rg -i "context:.+(\(.+\)|\".*\")" --glob "*.{ts,tsx,js,jsx,md,mdx}" # Check if any usage examples show nested query structures rg -i "example.*context:.+(and|or|not)" --glob "*.{md,mdx}"Length of output: 388
Handle nested query structures in transformZoektQuery
The current implementation simply does
query.split(" ")
, which will break on any quoted terms (e.g."foo bar"
) or parenthesized groups (e.g.(A OR B)
). We didn’t find any instances of nested or quotedcontext:
atoms in the docs or code, but if your search grammar supports grouping or quotes, this splitter will mis‐tokenize those queries.• Verify whether your UI or Zoekt query syntax allows quoted strings or Boolean/grouped expressions.
• If so, replace the ad-hoc.split(" ")
plus regex logic with a proper query‐AST parser (or reuse Sourcegraph’s existing query parser) so that you only rewrite therev:
,revision:
, andcontext:
atoms without losing nested structure.
• Update tests to cover cases like:
- context:"my context"
- (repo:foo OR repo:bar)
- -"complex term"
packages/web/src/ee/features/billing/actions.ts (1)
121-181
: Confirm whether any member should be allowed to initiate billing flows.
createStripeCheckoutSession
is guarded only by “is a member of org”, whereas sensitive actions (createOnboardingSubscription
,changeSubscriptionBillingEmail
) requireOrgRole.OWNER
.
If the intent is to restrict checkout to owners as well, add the role requirement:-withOrgMembership(session, domain, async ({ orgId }) => { +withOrgMembership(session, domain, async ({ orgId }) => { … -}, /* minRequiredRole = */ undefined) +}, /* minRequiredRole = */ OrgRole.OWNER)Please verify that the current behaviour matches product requirements.
packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
docs/self-hosting/more/search-contexts.mdx (1)
21-29
: Clarify group terminology
Nit: clarify thatweb
,backend
, andshared
refer to GitLab group namespaces rather than filesystem folders.
🧹 Nitpick comments (6)
packages/web/src/actions.ts (1)
1138-1152
: Well-implemented search contexts featureThe new
getSearchContexts
function follows the established patterns in the codebase:
- Uses the
sew
wrapper for consistent error handling- Properly implements authentication and authorization
- Allows single-tenant unauthenticated access, consistent with other query functions
Consider adding pagination if there could be a large number of search contexts per organization.
export const getSearchContexts = async (domain: string, options?: { limit?: number; offset?: number }) => sew(() => withAuth((session) => withOrgMembership(session, domain, async ({ orgId }) => { const searchContexts = await prisma.searchContext.findMany({ where: { orgId, }, + skip: options?.offset || 0, + take: options?.limit || 100, }); return { + searchContexts: searchContexts.map((context) => ({ name: context.name, description: context.description ?? undefined, })), + totalCount: await prisma.searchContext.count({ + where: { orgId } + }) }; } ), /* allowSingleTenantUnauthedAccess = */ true));docs/self-hosting/more/search-contexts.mdx (5)
1-4
: Enhance frontmatter metadata
Consider adding adescription
field to the frontmatter for better SEO, accessibility, and documentation navigation.
6-8
: Use a consistent admonition component
To align with other MDX patterns, consider replacing<Note>
with the standardized<Callout>
or<Alert>
component (if available) for improved styling and clarity.
17-18
: Improve phrasing
Replace “inside of a [declarative config]” with “in a [declarative config]” to remove redundancy.🧰 Tools
🪛 LanguageTool
[style] ~17-~17: This phrase is redundant. Consider using “inside”.
Context: ...xts are defined in thecontext
object inside of a [declarative config](/self-hosting/mo...(OUTSIDE_OF)
48-85
: Annotate JSON example
The inline comments (//
) improve readability but aren’t valid JSON syntax. Consider indicating that this is illustrative JSONC or remove comments from the actual config snippet.
100-100
: Add descriptive alt text
Replace![Example]
with a more descriptive alt text, e.g.,![Search contexts example illustrating context usage]
, to improve accessibility.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
docs/self-hosting/license-key.mdx
(1 hunks)docs/self-hosting/more/search-contexts.mdx
(1 hunks)packages/web/src/actions.ts
(6 hunks)packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx
(7 hunks)vendor/zoekt
(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- vendor/zoekt
- docs/self-hosting/license-key.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/web/src/app/[domain]/components/searchBar/searchSuggestionsBox.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/web/src/actions.ts (3)
packages/web/src/ee/features/billing/serverUtils.ts (3)
getSubscriptionForOrg
(53-80)incrementOrgSeatCount
(9-29)decrementOrgSeatCount
(31-51)packages/web/src/ee/features/billing/stripe.ts (1)
IS_BILLING_ENABLED
(6-6)packages/web/src/lib/utils.ts (1)
isServiceError
(151-157)
🪛 LanguageTool
docs/self-hosting/more/search-contexts.mdx
[style] ~17-~17: This phrase is redundant. Consider using “inside”.
Context: ...xts are defined in the context
object inside of a [declarative config](/self-hosting/mo...
(OUTSIDE_OF)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build
🔇 Additional comments (12)
packages/web/src/actions.ts (5)
29-29
: Good refactoring of billing-related importsThe code now properly centralizes and imports billing utility functions from the enterprise features directory, improving modularity and maintainability.
232-233
: Clean abstraction of subscription fetchingReplacing direct Stripe client calls with the centralized
getSubscriptionForOrg
utility function improves code organization and maintainability.
847-852
: Fixed transaction handling for seat incrementThe code now properly uses transactions with
throw
instead ofreturn
for error handling, addressing the previous race condition issue where Stripe seat count could be incremented without adding the member.
1004-1020
: Fixed seat-decrement and membership removal transactionThis implementation properly addresses the past review comment by keeping seat-decrement and membership removal within the same transaction. Using
throw
for errors ensures proper transaction rollback.
1049-1065
: Consistent transaction handling in leaveOrgThe same pattern of transaction handling is correctly applied here as in
removeMemberFromOrg
, ensuring atomicity between database operations and billing updates.docs/self-hosting/more/search-contexts.mdx (7)
10-15
: Clear definition and example queries
The introduction and sample queries effectively demonstrate how search contexts work.
23-40
: Illustrate repository structure clearly
The shell tree output provides a helpful visual, and using thetree
format is intuitive for readers.
42-47
: Context list is clear
Listing each context (web
,backend
,pipelines
) with brief descriptions helps readers understand how they map to repo groupings.
87-92
: Good use of Accordion
The<Accordion>
around repository URL details helps keep the guide concise while providing deeper context on demand.
95-98
: Strong usage examples
The bullet points effectively demonstrate how to apply contexts in search bar queries.
102-105
: Clear explanation of negation and combinations
The examples for excluding contexts and combining them withor
accurately show advanced query usage.
108-154
: Comprehensive schema reference
The JSON schema reference is thorough and aligns well with the code changes.
This PR adds support for search contexts as a enterprise feature (more on that below).
Overview
A search context is a user-defined grouping of repositories that helps focus searches on specific areas of your codebase, like frontend, backend, or infrastructure code. Some example queries using search contexts:
context:data_engineering userId
- search foruserId
across all repos related to Data Engineering.context:k8s ingress
- search for anything related to ingresses in your k8's configs.( context:project1 or context:project2 ) logger\.debug
- search for debug log calls in project1 and project2Search contexts are defined in the
context
object inside of a declarative config. Repositories can be included / excluded from a search context by specifying the repo's URL in either theinclude
array orexclude
array. Glob patterns are supported.Repository URL details
Repo URLs are expected to be formatted without the leading http(s):// prefix. For example:
github.com/sourcebot-dev/sourcebot
(link)gitlab.com/gitlab-org/gitlab
(link)chromium.googlesource.com/chromium
(link)Here's an example config that defines a search context:
Sourcebot enterprise TLDR
note: a more thorough [blog post](https://www.sourcebot.dev/blog) is on the way discussing this
This PR introduces our first paid feature as part of our "Sourcebot enterprise" offering. Functionally speaking, we are implementing this as a open-core model, where the core will continue to be licensed under MIT, and any paid features (like search contexts) will be licensed under a commercial license (see
ee/LICENSE
). This PR additionally moves the billing related code under the commercial license since it's only relevant for Sourcebot cloud.We want to be as transparent as possible with this, so as always, feel free to [open a discussion](https://github.com/sourcebot-dev/sourcebot/discussions) or [email us](mailto:team@sourcebot.dev) directly.
Fixes #81
Fixes #141