-
Notifications
You must be signed in to change notification settings - Fork 110
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
Replaces rate-limit, stripe-billing and usage-estimator with commerce #6540
base: main
Are you sure you want to change the base?
Conversation
Warning Rate limit exceeded@kamilkisiela has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 18 minutes and 0 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
📝 WalkthroughSummary by CodeRabbit
Summary by CodeRabbit
WalkthroughThe pull request consolidates and refactors several service modules by removing dedicated billing, rate limiting, and usage estimation implementations and replacing them with a unified commerce service. Deployment scripts, GraphQL modules, Docker configurations, environment templates, and package dependencies have been updated accordingly. Legacy functions, imports, and modules (such as deployStripeBilling, deployRateLimit, and usage estimator modules) were deleted while new commerce-specific functions, routers, TRPC clients, and configurations were introduced. TypeScript path mappings and documentation have also been revised to reflect the shift toward a commerce-focused architecture. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API_Gateway
participant TRPC_Client
participant Commerce_Service
Client->>API_Gateway: Send commerce-related request
API_Gateway->>TRPC_Client: Forward request via commerceRouter
TRPC_Client->>Commerce_Service: Process billing, rate limit, usage estimation
Commerce_Service-->>TRPC_Client: Return aggregated commerce data
TRPC_Client-->>API_Gateway: Relay response
API_Gateway-->>Client: Return final commerce response
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 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: 6
🧹 Nitpick comments (28)
packages/services/api/src/modules/commerce/providers/rate-limit.provider.ts (3)
48-48
: Delegated rate limit check has no explicit error handling.
It may be beneficial to handle errors that could arise fromcheckRateLimit.query(input)
. Consider adding try/catch or a fallback to handle upstream TRPC call failures gracefully.
52-52
: Duplicate null-check consideration.
This null-check is the same pattern used above. If there's a genuine scenario where the client might be null, consider consolidating or clarifying the fallback logic. Otherwise, remove for clarity.
62-62
: Add error handling or fallback logic for retrieving rate limit retention.
Similar to thecheckRateLimit
method, consider wrappinggetRetention.query(input)
in a try/catch block to manage potential TRPC client failures.packages/services/api/src/modules/commerce/providers/usage-estimation.provider.ts (1)
45-45
: Add error-handling fallback when estimating operations.
A try/catch or explicit error handler would protect against TRPC query failures.packages/services/commerce/src/index.ts (2)
55-59
: PostgreSQL storage creation.
Looks correct. Consider verifying if the pool size (5) is adequate for production load.
99-101
: Parallel shutdown of estimator, rate limiter, and Stripe billing.
Implementation is clean; however, consider handling partial failures if one stop call rejects.packages/services/api/src/modules/commerce/providers/billing.provider.ts (1)
2-2
: Remove the unused LRU import.
ESLint warns that 'LRU' is never used. Consider deleting the import.- import LRU from 'lru-cache';
🧰 Tools
🪛 GitHub Check: code-style / eslint-and-prettier
[failure] 2-2:
'LRU' is defined but never used. Allowed unused vars must match /^_/upackages/services/commerce/src/environment.ts (2)
64-70
: Introducing ClickHouseModel.The fields look comprehensive for ClickHouse use. Consider whether it needs optional SSL or other advanced config.
174-177
: Preserving “rate-limit” as a metric label might be misleading.Consider renaming
'rate-limit'
to'commerce'
or something relevant to the new consolidated service.- instance: prometheus.PROMETHEUS_METRICS_LABEL_INSTANCE ?? 'rate-limit', + instance: prometheus.PROMETHEUS_METRICS_LABEL_INSTANCE ?? 'commerce',packages/services/api/src/create.ts (1)
208-209
: Provider array includes InMemoryRateLimit{Store,Limiter}.Check that this approach is still relevant given the commerce refactor. Potential duplication or overlap?
packages/services/commerce/src/stripe-billing/index.ts (3)
164-164
: generateStripePortalLink procedure.Matches new TRPC style. Make sure
return_url
remains correct for your environment.
189-189
: cancelSubscriptionForOrganization procedure.Keep in mind proration might impact real-time usage.
226-226
: createSubscriptionForOrganization procedure.Large method. Ensure thorough testing for coupons, trials, and concurrency.
packages/services/commerce/src/trpc.ts (1)
1-12
: LGTM! Consider using Zod for request validation.The Context type and dependencies are well-structured. Given the coding guidelines preference for Zod, consider adding input validation using Zod schemas for the procedures.
Example usage with Zod:
import { z } from 'zod'; export const publicProcedure = t.procedure .use(handleTRPCError) .input(z.object({ // Define your input schema here }).optional());packages/services/api/src/modules/commerce/index.ts (1)
1-22
: LGTM! Consider adding module configuration validation.The commerce module setup is clean and well-structured, effectively consolidating all necessary providers. The inclusion of AuditLogManager shows good attention to operation tracking.
Consider adding configuration validation using Zod to ensure all required environment variables and settings are properly set:
import { z } from 'zod'; const CommerceConfig = z.object({ // Define your config schema here }); export const commerceModule = createModule({ id: 'commerce', dirname: __dirname, typeDefs, resolvers, providers: [ { provide: 'COMMERCE_CONFIG', useValue: CommerceConfig.parse({ // Your config here }), }, BillingProvider, RateLimitProvider, UsageEstimationProvider, AuditLogManager, provideCommerceClient(), ], });packages/services/commerce/src/rate-limit/index.ts (1)
16-31
: Consider adding error handling and rate limit validation.While the implementation is functionally correct, consider adding:
- Error handling for potential failures in
ctx.rateLimiter
calls- Input validation for the time range between
startTime
andendTime
checkRateLimit: publicProcedure.input(VALIDATION).query(({ ctx, input }) => { - return ctx.rateLimiter.checkLimit(input); + try { + return ctx.rateLimiter.checkLimit(input); + } catch (error) { + ctx.logger.error('Failed to check rate limit', { error, input }); + throw error; + } }),packages/services/api/src/modules/commerce/providers/commerce-client.ts (1)
23-38
: Consider adding retry logic and timeout configuration.The TRPC client configuration could benefit from additional error handling and performance optimizations.
return createTRPCProxyClient<CommerceRouter>({ - links: [httpLink({ url: `${config.endpoint}/trpc`, fetch })], + links: [ + httpLink({ + url: `${config.endpoint}/trpc`, + fetch, + headers: () => ({ + 'x-request-id': crypto.randomUUID(), + }), + timeout: 10000, // 10s timeout + }), + ], });packages/services/commerce/src/usage-estimator/estimator.ts (1)
67-67
: Consider making query timeouts configurable.The hardcoded timeout values (
60_000
and15_000
) should be configurable to accommodate different environments and load conditions.Consider adding timeout configuration:
export function createEstimator(config: { logger: ServiceLogger; clickhouse: { protocol: string; host: string; port: number; username: string; password: string; + queryTimeouts?: { + estimateOperationsForAllTargets?: number; + estimateCollectedOperationsForOrganization?: number; + }; }; })Also applies to: 89-89
packages/services/api/src/modules/commerce/resolvers/Organization.ts (1)
116-139
: Consider enhancing error handling and logging.While the implementation is solid, consider these improvements:
- Use a more specific error type check (e.g.,
instanceof RateLimitError
).- Add more context to debug logs about why an organization is rate-limited.
- Consider logging a warning instead of error when rate limit info fetch fails, as it's handled gracefully.
rateLimit: async (org, _args, { injector }) => { let limitedForOperations = false; const logger = injector.get(Logger); try { const operationsRateLimit = await injector.get(RateLimitProvider).checkRateLimit({ entityType: 'organization', id: org.id, type: 'operations-reporting', token: null, }); - logger.debug('Fetched rate-limit info:', { orgId: org.id, operationsRateLimit }); + logger.debug('Rate-limit status:', { + orgId: org.id, + usagePercentage: operationsRateLimit.usagePercentage, + isLimited: operationsRateLimit.usagePercentage >= 1, + limit: org.monthlyRateLimit.operations, + }); limitedForOperations = operationsRateLimit.usagePercentage >= 1; } catch (e) { - logger.error('Failed to fetch rate-limit info:', org.id, e); + logger.warn('Failed to fetch rate-limit info:', { + orgId: org.id, + error: e instanceof Error ? e.message : String(e), + }); } return { limitedForOperations, operations: org.monthlyRateLimit.operations, retentionInDays: org.monthlyRateLimit.retentionInDays, }; },packages/services/usage/src/environment.ts (1)
25-25
: Consider renaming RATE_LIMIT_TTL for clarity.The
RATE_LIMIT_TTL
environment variable is still used in the commerce configuration but its name doesn't reflect its new context. Consider renaming it to align with the commerce service consolidation.const EnvironmentModel = zod.object({ PORT: emptyString(NumberFromString.optional()), TOKENS_ENDPOINT: zod.string().url(), COMMERCE_ENDPOINT: emptyString(zod.string().url().optional()), - RATE_LIMIT_TTL: emptyString(NumberFromString.optional()).default(30_000), + COMMERCE_RATE_LIMIT_TTL: emptyString(NumberFromString.optional()).default(30_000), ENVIRONMENT: emptyString(zod.string().optional()), RELEASE: emptyString(zod.string().optional()), }); // Later in the code... commerce: base.COMMERCE_ENDPOINT ? { endpoint: base.COMMERCE_ENDPOINT, - ttl: base.RATE_LIMIT_TTL, + ttl: base.COMMERCE_RATE_LIMIT_TTL, } : null,Also applies to: 149-154
packages/services/commerce/src/rate-limit/limiter.ts (1)
7-7
: Remove commented-out import.The commented-out import of
RateLimitInput
should be removed as it's no longer needed.-// import type { RateLimitInput } from './api';
packages/services/server/src/environment.ts (1)
375-380
: Consider making the purge interval configurable.The
dateRetentionPurgeIntervalMinutes
is hardcoded to 5 minutes. Consider making this configurable through an environment variable to allow for flexibility in different environments.Apply this diff to make the interval configurable:
- dateRetentionPurgeIntervalMinutes: 5, + dateRetentionPurgeIntervalMinutes: commerce.COMMERCE_DATE_RETENTION_PURGE_INTERVAL_MINUTES ?? 5,And add the following to the
CommerceModel
schema:const CommerceModel = zod.object({ COMMERCE_ENDPOINT: emptyString(zod.string().url().optional()), + COMMERCE_DATE_RETENTION_PURGE_INTERVAL_MINUTES: emptyString(NumberFromString.optional()), });
packages/services/commerce/.env.template (1)
15-15
: Consider using a more descriptive placeholder for the Stripe secret key.The default value "empty" for
STRIPE_SECRET_KEY
might be confusing. Consider using a more descriptive placeholder that indicates it needs to be replaced with a real key.Apply this diff to make the placeholder more descriptive:
-STRIPE_SECRET_KEY="empty" +STRIPE_SECRET_KEY="<your-stripe-secret-key>"packages/services/commerce/README.md (1)
1-3
: Improve Documentation Clarity
The opening sentence is slightly unclear. Consider updating “This service takes care of commerce part of Hive Cloud.” to “This service takes care of the commerce part of Hive Cloud.” for improved readability.🧰 Tools
🪛 LanguageTool
[uncategorized] ~3-~3: You might be missing the article “the” here.
Context: ...e/commerce` This service takes care of commerce part of Hive Cloud. ## Configuration ...(AI_EN_LECTOR_MISSING_DETERMINER_THE)
packages/services/usage/README.md (1)
14-14
: Review Commerce Endpoint Configuration
The addition of theCOMMERCE_ENDPOINT
configuration option is appropriate given the service consolidation. However, please verify that the example value (http://127.0.0.1:4012
) matches the intended deployment configuration and is consistent with documentation in other areas (such as integration tests).integration-tests/docker-compose.integration.yaml (1)
114-144
: Addition of Commerce Service in Integration Tests
The newcommerce
service block is well integrated. It correctly specifies the image, dependencies (clickhouse, migrations, emails), and network settings. Please ensure that setting theSTRIPE_SECRET_KEY
toempty
is intentional and that all environment variables (including the assigned port) are correctly aligned with the commerce service’s requirements.docker/docker.hcl (1)
207-226
: Validate Commerce Target Configuration
The newcommerce
target is properly defined with the correct context (${PWD}/packages/services/commerce/dist
) and appropriate service details. Note that the target setsPORT = "3010"
, which differs from the port mapping (e.g., 3009) used in the integration tests configuration. Please verify that this discrepancy is intended and, if so, document the reasoning for clarity.packages/services/server/README.md (1)
102-107
: Review of Internal Service Keys and Usage/Reporting Endpoints
This block defines several internal configuration parameters (HIVE
,HIVE_API_TOKEN
,HIVE_USAGE
,HIVE_USAGE_ENDPOINT
,HIVE_REPORTING
, andHIVE_REPORTING_ENDPOINT
). Given the consolidation of services into a unified commerce module, please verify:
- That the roles and naming of
HIVE_USAGE
andHIVE_USAGE_ENDPOINT
still accurately reflect the current usage reporting mechanism.- Whether the descriptions for
HIVE
andHIVE_API_TOKEN
could be made more explicit (e.g. clarifying what is meant by “internal endpoint key”) to aid future maintainers.If these parameters are legacy remnants, consider updating their documentation or deprecating them accordingly.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (81)
deployment/index.ts
(5 hunks)deployment/services/app.ts
(4 hunks)deployment/services/commerce.ts
(5 hunks)deployment/services/graphql.ts
(5 hunks)deployment/services/rate-limit.ts
(0 hunks)deployment/services/usage-estimation.ts
(0 hunks)deployment/services/usage.ts
(5 hunks)docker/docker.hcl
(2 hunks)integration-tests/.env
(1 hunks)integration-tests/docker-compose.integration.yaml
(4 hunks)integration-tests/package.json
(1 hunks)packages/services/api/package.json
(1 hunks)packages/services/api/src/create.ts
(8 hunks)packages/services/api/src/modules/billing/index.ts
(0 hunks)packages/services/api/src/modules/billing/module.graphql.mappers.ts
(0 hunks)packages/services/api/src/modules/billing/providers/tokens.ts
(0 hunks)packages/services/api/src/modules/commerce/index.ts
(1 hunks)packages/services/api/src/modules/commerce/module.graphql.mappers.ts
(1 hunks)packages/services/api/src/modules/commerce/module.graphql.ts
(3 hunks)packages/services/api/src/modules/commerce/providers/billing.provider.ts
(5 hunks)packages/services/api/src/modules/commerce/providers/commerce-client.ts
(1 hunks)packages/services/api/src/modules/commerce/providers/rate-limit.provider.ts
(4 hunks)packages/services/api/src/modules/commerce/providers/usage-estimation.provider.ts
(2 hunks)packages/services/api/src/modules/commerce/resolvers/Organization.ts
(2 hunks)packages/services/api/src/modules/organization/providers/organization-manager.ts
(1 hunks)packages/services/api/src/modules/organization/resolvers/Mutation/inviteToOrganizationByEmail.ts
(1 hunks)packages/services/api/src/modules/rate-limit/index.ts
(0 hunks)packages/services/api/src/modules/rate-limit/module.graphql.ts
(0 hunks)packages/services/api/src/modules/rate-limit/providers/tokens.ts
(0 hunks)packages/services/api/src/modules/rate-limit/resolvers/Organization.ts
(0 hunks)packages/services/api/src/modules/schema/providers/schema-publisher.ts
(1 hunks)packages/services/api/src/modules/shared/providers/in-memory-rate-limiter.ts
(1 hunks)packages/services/api/src/modules/usage-estimation/index.ts
(0 hunks)packages/services/api/src/modules/usage-estimation/module.graphql.ts
(0 hunks)packages/services/api/src/modules/usage-estimation/providers/tokens.ts
(0 hunks)packages/services/commerce/.env.template
(1 hunks)packages/services/commerce/.gitignore
(1 hunks)packages/services/commerce/LICENSE
(1 hunks)packages/services/commerce/README.md
(1 hunks)packages/services/commerce/package.json
(2 hunks)packages/services/commerce/src/api.ts
(1 hunks)packages/services/commerce/src/environment.ts
(5 hunks)packages/services/commerce/src/index.ts
(5 hunks)packages/services/commerce/src/rate-limit/emails.ts
(1 hunks)packages/services/commerce/src/rate-limit/index.ts
(1 hunks)packages/services/commerce/src/rate-limit/limiter.ts
(7 hunks)packages/services/commerce/src/stripe-billing/billing.ts
(2 hunks)packages/services/commerce/src/stripe-billing/index.ts
(20 hunks)packages/services/commerce/src/trpc.ts
(1 hunks)packages/services/commerce/src/usage-estimator/estimator.ts
(5 hunks)packages/services/commerce/src/usage-estimator/index.ts
(1 hunks)packages/services/rate-limit/.env.template
(0 hunks)packages/services/rate-limit/README.md
(0 hunks)packages/services/rate-limit/package.json
(0 hunks)packages/services/rate-limit/src/api.ts
(0 hunks)packages/services/rate-limit/src/environment.ts
(0 hunks)packages/services/rate-limit/src/index.ts
(0 hunks)packages/services/rate-limit/tsconfig.json
(0 hunks)packages/services/server/.env.template
(2 hunks)packages/services/server/README.md
(1 hunks)packages/services/server/src/api.ts
(1 hunks)packages/services/server/src/environment.ts
(4 hunks)packages/services/server/src/index.ts
(5 hunks)packages/services/service-common/src/trpc.ts
(1 hunks)packages/services/stripe-billing/.env.template
(0 hunks)packages/services/stripe-billing/README.md
(0 hunks)packages/services/stripe-billing/src/dev.ts
(0 hunks)packages/services/stripe-billing/src/index.ts
(0 hunks)packages/services/tokens/README.md
(0 hunks)packages/services/usage-estimator/README.md
(0 hunks)packages/services/usage-estimator/package.json
(0 hunks)packages/services/usage-estimator/src/api.ts
(0 hunks)packages/services/usage-estimator/src/dev.ts
(0 hunks)packages/services/usage-estimator/src/environment.ts
(0 hunks)packages/services/usage-estimator/tsconfig.json
(0 hunks)packages/services/usage/.env.template
(1 hunks)packages/services/usage/README.md
(1 hunks)packages/services/usage/src/environment.ts
(2 hunks)packages/services/usage/src/index.ts
(1 hunks)packages/services/usage/src/rate-limit.ts
(4 hunks)tsconfig.json
(1 hunks)
💤 Files with no reviewable changes (30)
- packages/services/usage-estimator/tsconfig.json
- packages/services/api/src/modules/usage-estimation/index.ts
- packages/services/api/src/modules/billing/index.ts
- packages/services/usage-estimator/src/dev.ts
- packages/services/rate-limit/tsconfig.json
- packages/services/tokens/README.md
- packages/services/stripe-billing/src/dev.ts
- packages/services/api/src/modules/rate-limit/providers/tokens.ts
- packages/services/api/src/modules/usage-estimation/module.graphql.ts
- packages/services/rate-limit/src/index.ts
- deployment/services/usage-estimation.ts
- packages/services/rate-limit/package.json
- packages/services/api/src/modules/billing/providers/tokens.ts
- packages/services/api/src/modules/rate-limit/index.ts
- packages/services/usage-estimator/package.json
- packages/services/rate-limit/.env.template
- packages/services/api/src/modules/rate-limit/module.graphql.ts
- packages/services/rate-limit/README.md
- packages/services/stripe-billing/src/index.ts
- packages/services/usage-estimator/README.md
- packages/services/api/src/modules/rate-limit/resolvers/Organization.ts
- packages/services/api/src/modules/billing/module.graphql.mappers.ts
- packages/services/rate-limit/src/environment.ts
- packages/services/usage-estimator/src/api.ts
- packages/services/stripe-billing/README.md
- packages/services/usage-estimator/src/environment.ts
- packages/services/api/src/modules/usage-estimation/providers/tokens.ts
- packages/services/stripe-billing/.env.template
- deployment/services/rate-limit.ts
- packages/services/rate-limit/src/api.ts
✅ Files skipped from review due to trivial changes (7)
- packages/services/commerce/.gitignore
- packages/services/commerce/src/rate-limit/emails.ts
- packages/services/commerce/LICENSE
- packages/services/api/src/modules/shared/providers/in-memory-rate-limiter.ts
- packages/services/api/src/modules/organization/resolvers/Mutation/inviteToOrganizationByEmail.ts
- packages/services/api/src/modules/organization/providers/organization-manager.ts
- packages/services/api/src/modules/schema/providers/schema-publisher.ts
🧰 Additional context used
📓 Path-based instructions (4)
`packages/services/**`: Microservices written in NodeJS and ...
packages/services/**
: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with-worker
are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
Thecdn-worker
is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).
packages/services/commerce/src/api.ts
packages/services/api/package.json
packages/services/commerce/src/usage-estimator/index.ts
packages/services/api/src/modules/commerce/index.ts
packages/services/usage/src/index.ts
packages/services/commerce/README.md
packages/services/server/README.md
packages/services/usage/src/environment.ts
packages/services/api/src/modules/commerce/module.graphql.mappers.ts
packages/services/commerce/src/trpc.ts
packages/services/api/src/modules/commerce/resolvers/Organization.ts
packages/services/service-common/src/trpc.ts
packages/services/commerce/src/usage-estimator/estimator.ts
packages/services/usage/README.md
packages/services/commerce/src/rate-limit/index.ts
packages/services/commerce/package.json
packages/services/usage/src/rate-limit.ts
packages/services/server/src/api.ts
packages/services/api/src/modules/commerce/providers/rate-limit.provider.ts
packages/services/api/src/modules/commerce/providers/usage-estimation.provider.ts
packages/services/api/src/create.ts
packages/services/server/src/environment.ts
packages/services/commerce/src/stripe-billing/billing.ts
packages/services/commerce/src/stripe-billing/index.ts
packages/services/api/src/modules/commerce/module.graphql.ts
packages/services/commerce/src/index.ts
packages/services/server/src/index.ts
packages/services/api/src/modules/commerce/providers/billing.provider.ts
packages/services/commerce/src/rate-limit/limiter.ts
packages/services/api/src/modules/commerce/providers/commerce-client.ts
packages/services/commerce/src/environment.ts
`**/.env.template`: When a `.env.template` file changes, it'...
**/.env.template
: When a.env.template
file changes, it's usually because we added/removed an environment variable from a service.
Please ensure that the service'sREADME.md
file also includes changes to reflect the changes.
Also, make sure that all Docker Compose file that are using the service are also up to date with default values.
Also validate indeployment/
directory that the service's IaC deployment code is up to date.
packages/services/usage/.env.template
packages/services/commerce/.env.template
packages/services/server/.env.template
`integration-tests/**`: integration tests for ensuring featu...
integration-tests/**
: integration tests for ensuring features and important flows are running. Usually, changes to thepackages/
directory will affect this. In ideal flow, each PR should include integration tests.
integration-tests/package.json
integration-tests/docker-compose.integration.yaml
`deployment/**`: infrastructure-as-code written in TypeScrip...
deployment/**
: infrastructure-as-code written in TypeScript using Pulumi. Deploys resources to CloudFlare, Azure, AWS.
deployment/index.ts
deployment/services/app.ts
deployment/services/usage.ts
deployment/services/graphql.ts
deployment/services/commerce.ts
🪛 LanguageTool
packages/services/commerce/README.md
[uncategorized] ~3-~3: You might be missing the article “the” here.
Context: ...e/commerce` This service takes care of commerce part of Hive Cloud. ## Configuration ...
(AI_EN_LECTOR_MISSING_DETERMINER_THE)
🪛 GitHub Check: code-style / eslint-and-prettier
packages/services/api/src/modules/commerce/providers/billing.provider.ts
[failure] 2-2:
'LRU' is defined but never used. Allowed unused vars must match /^_/u
⏰ Context from checks skipped due to timeout of 90000ms (7)
- GitHub Check: typescript / typecheck
- GitHub Check: static-analysis / analyze (typescript)
- GitHub Check: static-analysis / analyze (javascript)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
- GitHub Check: code-style / eslint-and-prettier
- GitHub Check: alpha / cli-artifacts
🔇 Additional comments (139)
packages/services/api/src/modules/commerce/providers/rate-limit.provider.ts (4)
4-8
: Imports aligned with the new commerce client structure.
No issues spotted. The import statements cleanly reference the newCommerceTrpcClient
types, matching the broader shift to the commerce-based architecture.
10-10
: Clearer typing for rate limit inputs.
DefiningRateLimitApiInput
as an alias toCommerceTrpcClientInputs['rateLimit']
provides clarity and maintainability. No concerns.
28-28
: Successful integration of the commerce TRPC client via dependency injection.
Switching from a service-specific config to a unifiedCommerceTrpcClient
injection aligns well with the new commerce-centric design.
34-34
: Potential redundancy in null-checking the injected client.
If the@Inject(COMMERCE_TRPC_CLIENT)
always provides a valid instance, consider removing this check or throwing an error if the situation truly indicates a misconfiguration.packages/services/api/src/modules/commerce/providers/usage-estimation.provider.ts (3)
6-6
: Updated imports for commerce client usage.
No issues here. The new import aligns with commerce-based usage estimation.
16-17
: Injection of the unified commerce TRPC client.
Replacing the old config-based approach with a directCommerceTrpcClient
simplifies the logic. Looks good.
39-39
: Potentially unnecessary null-check for an always-injected client.
If the@Inject(COMMERCE_TRPC_CLIENT)
reliably provides a valid instance, consider removing this check or treating it as a fatal error.deployment/services/commerce.ts (9)
5-5
: New Clickhouse import recognized.
Inclusion of Clickhouse presumably aligns with broader analytics or data storage strategies.
8-8
: Adding Emails module to the commerce service scope.
Reflects the combined approach for billing/commerce functionalities, including email integration.
14-14
: Exported CommerceService type for easier references.
Straightforward approach that helps unify type usage across the codebase.
21-21
: Refactored function signature to host the new commerce environment parameters.
Incorporatingemails
andclickhouse
as arguments is consistent with the new consolidated commerce requirement. No issues spotted.Also applies to: 25-25, 29-29, 37-37, 39-39
48-48
: Rename from 'stripe-billing' to 'commerce'.
Clear naming for the new consolidated service.
59-59
: Setting environment variables for email, web app URL, and usage tracing.
Straightforward usage of environment variables. Consider ensuring these align with the final production configuration.Also applies to: 60-60, 61-61
70-70
: Including DB migrations dependency.
This ensures database migrations run before commerce service starts. No concerns spotted.
79-83
: Secrets for managing Clickhouse connection configuration.
Good approach to keep sensitive data in secrets. Ensure the connection is properly tested in staging.
90-90
: Returning stripeSecret in the commerce deployment output.
Retaining Stripe secret usage ensures backward compatibility with existing billing flows until fully replaced.packages/services/commerce/src/index.ts (10)
12-18
: Good use of newly introduced imports for commerce architecture.
These imports integrate well with your refactoring from usage-estimator to commerce, rate-limiter, and Stripe billing.
26-26
: Service name updated to 'commerce'.
This change keeps naming consistent with the refactored service.
37-37
: Sentry 'dist' set to 'commerce'.
No issues here; aligns Sentry distribution with the new service name.
46-46
: Server name set to 'commerce'.
Matches the new consolidated commerce service.
61-70
: Usage estimator setup.
Configuration with ClickHouse credentials appears correct.
72-84
: Creation of rate limiter with usage estimator and email integration.
Implementation is coherent with the new commerce refactor.
86-94
: Stripe billing initialization.
Properly references the environment and storage.
105-114
: Register TRPC with commerce router.
Context injection for usageEstimator, rateLimiter, and stripeBilling is consistent.
128-134
: Comprehensive readiness checks.
All necessary dependencies are validated.
147-147
: Concurrent startup of usageEstimator, rateLimiter, and stripeBilling.
Approach is typical; verify logs to ensure no partial start issues.packages/services/usage/src/rate-limit.ts (4)
2-2
: Importing CommerceRouter type.
Switching to the new router aligns with the commerce refactor.
72-72
: TRPC client creation using CommerceRouter.
Properly configured for the new commerce endpoint with a 5s timeout.
101-101
: QueryingrateLimit.checkRateLimit
from commerceClient.
Usage of final block to stop timing metric is accurate.
133-133
: Retrieving retention from the commerce rateLimit router.
Consistently replaces old rate-limit API calls with the commerce API.packages/services/api/src/modules/commerce/providers/billing.provider.ts (17)
9-13
: Introduction of CommerceTrpcClient imports.
Successfully replaces old Stripe billing-related imports.
15-15
: BillingInput type added.
Facilitates typed interactions with the commerce TRPC layer.
19-19
: Global scope at operation level.
Ensures the provider is available globally during GraphQL operations.
27-27
: Injecting CommerceTrpcClient.
Good practice for clean dependency injection.
34-34
: Logger child source set to 'CommerceProvider'.
Clarifies log origin after the refactor.
36-36
: Feature toggle using!!client
.
Enabled property is straightforward and consistent.
39-39
:upgradeToPro
method signature changed to new BillingInput.
Adapts to commerce TRPC model for subscriptions.
41-41
: Guarding against uninitialized client.
Helps avoid runtime errors when billing is misconfigured.
45-45
: Mutation call tocreateSubscriptionForOrganization
.
Correct transition from older billing API.
61-66
:syncOrganization
method with new commerce-based mutation.
Replaces direct Stripe calls with commerce service calls.
75-75
:getAvailablePrices
callsstripeBilling.availablePrices.query()
.
Gracefully returns null whenclient
is unavailable.
88-94
:getActiveSubscription
using commerce client.
Ensures consistent subscription queries in the new architecture.
97-103
:invoices
method referencingstripeBilling.invoices
.
No issues with the refactored approach.
106-112
:upcomingInvoice
method.
Accurate pivot to commerce-based query.
115-130
: Downgrade to Hobby flow.
Auditing logic remains intact, aligned with new TRPC calls.
133-136
:generateStripePortalLink
with commerce client fallback.
Confirms the client's existence before proceeding.
152-152
: Final TRPC call for generating the portal link.
No logical issues. Auditing is performed beforehand.packages/services/commerce/src/environment.ts (15)
11-11
: Good environment parsing for numeric values.Exporting
NumberFromString
withmin(1)
helps ensure a positive integer environment variable. This looks correct.
13-16
: Clear empty-string-to-undefined handling.Good job providing a JSDoc and exporting
emptyString
. This clarifies the expected transformation from''
toundefined
.
42-42
: Optional numeric port setting.
PROMETHEUS_METRICS_PORT
is allowed to be optional. Ensure you handle defaults consistently in downstream code.
72-79
: Refined PostgresModel.Properties cover standard Postgres config. Ensure
POSTGRES_SSL
is respected properly at runtime.
81-84
: HiveServicesModel addition.Provides a consistent approach for environment-based service endpoints. Nothing concerning here.
86-88
: RateLimitModel structure is straightforward.Includes a single field for interval. Verify that the environment variable is set for any usage.
90-93
: StripeModel for commerce integration.Captures key elements: secret key and sync interval. Keep secrets secured properly in production.
95-105
: Safe parsing of environment configs.Adding the new service models (
clickhouse
,postgres
, etc.) ensures typed environment validation. Good move.
130-130
: Extracted clickhouse config.Using
extractConfig()
ensures type safety for the ClickHouse environment.
136-139
: Integrating hiveServices, rateLimit, and stripe.The extraction for these new environment blocks looks seamless; environment misconfigurations will be caught early.
144-144
: HTTP port default changed to 4012.Check for conflicts with any existing service or Docker config referencing the old port (4013).
150-155
: Expose ClickHouse config.All relevant fields are properly forwarded. Confirm that any disallowed special characters in the password are handled.
179-184
: New hiveServices config block.Small but clear. This helps unify environment-based setups for email and app URL.
185-187
: Rate-limit configuration in consolidated service.Double-check if this is still needed or if further unification is planned under “commerce.”
189-191
: Stripe environment block.Allows easy override of secret key and synchronization interval. Looks straightforward.
packages/services/api/src/create.ts (7)
17-17
: Added commerceModule import.Incorporating
commerceModule
unifies billing and rate-limiting logic under commerce.
18-21
: Importing CommerceConfig and provideCommerceConfig.This ensures commerce features are injected similarly to other modules (CDN, etc.).
52-55
: In-memory rate limiter imports.May conflict with the newly unified commerce approach if a separate rate limit strategy is used. Ensure consistency.
84-84
: Added commerceModule to modules array.Seamless new entry for commerce-based logic.
94-94
: 'commerce' parameter introduced for createRegistry.Replaces older billing/rate-limit parameters. Matches the new consolidated design.
120-120
: CommerceConfig in createRegistry’s signature.Reflects the direct injection of commerce environment variables.
298-298
: Providing commerce config.Ties environment-based commerce settings into GraphQL Modules. Straightforward injection.
packages/services/commerce/src/stripe-billing/index.ts (30)
4-5
: Switch to publicProcedure with TRPC.Using
publicProcedure
and the newrouter
is consistent with the approach in tRPC v10.
6-8
: Renamed router to stripeBillingRouter.The naming is succinct, but confirm usage across the codebase.
10-10
: Query for invoices procedure.Calling
publicProcedure
aligns with the newly consolidated commerce structure.
17-17
: Accessing ctx.stripeBilling.storage.Switch from
ctx.storage$
toctx.stripeBilling.storage
clarifies the commerce-specific context usage.
26-26
: Invoices list call references new consolidated Stripe object.Correct reference to
ctx.stripeBilling.stripe
.
33-34
: upcomingInvoice within publicProcedure.Retains prior logic; ensure the newly consolidated context is thoroughly tested.
40-40
: Again, consistent usage of ctx.stripeBilling.storage.Reduces confusion by centralizing storage references.
50-50
: Retrieve upcoming invoice from consolidated Stripe context.No concerns; continues prior functionality.
59-59
: activeSubscription publicProcedure.Follows the same pattern, hooking into consolidated commerce.
66-66
: Fetching organization billing via ctx.stripeBilling.storage.Logical context scoping to keep data in the same place.
75-75
: Retrieving Stripe customer from new context.Implementation remains straightforward.
87-87
: Listing Stripe subscriptions from commerce context.No issues spotted.
95-95
: Listing payment methods.Proper usage with consolidated
ctx.stripeBilling.stripe
.
105-105
: syncOrganizationToStripe now a publicProcedure.Exposes synchronization logic for external calls. Make sure concurrency is handled if multiple calls occur.
118-118
: Storing references in consolidated context.Consistent approach.
126-126
: Referencing ctx.stripeBilling.stripeData$.Ensure
stripeData$
is always available before usage.
130-130
: Listing subscriptions from consolidated Stripe instance.All logic is from previous flow, adapted to new context.
139-139
: Updating subscription items with new quantity.Verify that item IDs are valid in concurrency scenarios (e.g., user changes plan).
153-153
: Updating Stripe customer’s email and other fields.Double-check error handling for partial updates.
171-171
: Using ctx.stripeBilling.storage in portal link generation.Consistent usage. No issues found.
182-182
: Creating billing portal session with consolidated stripe.Ensure you handle user feedback if portal creation fails.
196-196
: ctx.stripeBilling.storage for subscription cancellation.Continuing the consolidated approach; code looks consistent.
207-207
: Fetching subscription list prior to cancellation.No immediate issues.
220-220
: Graceful subscription cancellation with proration.Ensure the rest of the system is aware of partial charges.
241-241
: Repeated pattern: use of ctx.stripeBilling.storage.Maintains consistency across the commerce approach.
274-274
: Listing payment methods from consolidated context.No issues.
291-291
: Attaching new payment method to the customer.Consider potential error cases if a payment method is invalid or revoked.
306-306
: Loading stripePrices from ctx.stripeBilling.Double-check that stripe prices are properly refreshed or cached.
308-308
: Creating a new subscription with multiple items.Ensure correct usage in multi-tenant or multiple-subscription scenarios.
337-337
: Exporting StripeBillingRouter type.Facilitates type-safe usage in tRPC consumers.
packages/services/api/src/modules/commerce/module.graphql.mappers.ts (1)
1-5
: LGTM! Clean and well-structured type mappings.The type mappings are correctly defined and align well with Stripe's type definitions. This provides good type safety for the billing functionality within the commerce module.
packages/services/commerce/src/api.ts (1)
1-12
: LGTM! Well-structured router composition.The commerce router effectively consolidates the three services (usage estimator, rate limit, and stripe billing) into a single, organized router. This aligns perfectly with the PR's objective of service consolidation.
packages/services/commerce/src/rate-limit/index.ts (2)
4-14
: LGTM! Well-structured input validation schema.The schema effectively validates the required fields with appropriate constraints and includes clear documentation for optional fields.
33-33
: LGTM! Type export follows best practices.The type export enables proper type inference for consumers of this router.
packages/services/api/src/modules/commerce/providers/commerce-client.ts (1)
1-10
: LGTM! Well-defined types with clear dependencies.The type definitions are clear and properly leverage TRPC's type inference capabilities.
packages/services/service-common/src/trpc.ts (1)
8-11
: LGTM! Improved type safety with explicit context constraint.The added type constraint ensures that the context type matches the router's expected context type, preventing potential type mismatches.
packages/services/commerce/src/usage-estimator/index.ts (1)
53-53
: LGTM! Type export follows best practices.The type export enables proper type inference for consumers of this router.
packages/services/server/src/api.ts (1)
7-10
: LGTM! The Context type definition is now more explicit.The direct type definition improves code clarity and removes unnecessary function indirection while maintaining type safety.
packages/services/commerce/src/stripe-billing/billing.ts (1)
70-72
: Verify the readiness check implementation.The readiness check now always returns
true
without verifying the actual state of dependencies. This could mask potential issues during service startup.Consider implementing proper readiness checks for:
- Storage connection
- Stripe API connectivity
- Usage estimator availability
packages/services/api/src/modules/commerce/module.graphql.ts (1)
112-130
: LGTM! Well-structured GraphQL types for rate limiting and usage estimation.The new types are well-designed with:
- Clear field names and types
- Proper input validation through non-null fields
- Consistent naming conventions
deployment/services/app.ts (1)
5-5
: LGTM! Clean transition from billing to commerce service.The changes consistently replace billing-related configurations with commerce ones, maintaining the same functionality while consolidating the services.
Also applies to: 26-26, 38-38, 82-82
deployment/services/usage.ts (1)
4-4
: LGTM! Clean transition from rate-limit to commerce service.The changes consistently replace rate-limit configurations with commerce ones, maintaining the same functionality while consolidating the services.
Also applies to: 20-20, 32-32, 69-69, 88-90
deployment/services/graphql.ts (4)
7-7
: LGTM!The import of
CommerceService
aligns with the PR's objective of consolidating billing and rate-limit services into a unified commerce service.
44-44
: LGTM!The addition of the
commerce
parameter to thedeployGraphQL
function signature and its type definition is consistent with the service consolidation pattern.Also applies to: 75-75
122-122
: LGTM!The addition of
COMMERCE_ENDPOINT
environment variable follows the same pattern as other service endpoints.
161-162
: LGTM!The addition of commerce service dependencies ensures proper service initialization order.
packages/services/commerce/src/rate-limit/limiter.ts (3)
2-2
: LGTM!The import of
Storage
type from@hive/api
improves type safety and modularity.
6-6
: LGTM!The import of
UsageEstimator
from the local module maintains proper module boundaries within the commerce service.
46-46
: LGTM!The rename from
Limiter
toRateLimiter
improves type naming clarity.deployment/index.ts (3)
7-7
: LGTM!The import of
deployCommerce
aligns with the PR's objective of consolidating services.
149-159
: LGTM!The deployment of the commerce service follows the same pattern as other services and includes all necessary dependencies.
168-168
: LGTM!The updates to usage, graphql, and app service dependencies to use the new commerce service are consistent with the service consolidation.
Also applies to: 221-221, 280-280
packages/services/usage/src/index.ts (1)
108-112
: LGTM!The update to use commerce configuration for rate limiting aligns with the service consolidation while maintaining the same functionality and fallback behavior.
packages/services/server/src/environment.ts (1)
47-49
: LGTM! The new CommerceModel schema follows the established pattern.The schema correctly validates the
COMMERCE_ENDPOINT
environment variable using the same pattern as other service endpoints.packages/services/server/src/index.ts (2)
188-193
: LGTM! The purge task scheduling logic has been updated correctly.The code properly checks for the commerce service availability and logs appropriate debug messages.
483-487
: LGTM! The TRPC context has been simplified.The context now only includes the essential dependencies (
storage
andcrypto
).packages/services/usage/.env.template (1)
9-9
: LGTM! The endpoint has been updated to point to the commerce service.The
COMMERCE_ENDPOINT
correctly points to the new commerce service port (4013).integration-tests/.env (1)
18-18
: Addition of COMMERCE_ENDPOINT
The newCOMMERCE_ENDPOINT=http://commerce:3009
is added as expected, replacing the deprecated usage-estimator and rate-limit endpoints. Please ensure that related integration scripts, tests, and documentation are updated accordingly.packages/services/commerce/package.json (3)
1-2
: Updated Package Name to @hive/commerce
The package has been renamed from@hive/stripe-billing
to@hive/commerce
to reflect the consolidated service architecture. Please double-check that all internal references and documentation align with this change.
12-13
: New Dev Dependencies Added
Adding"@hive/api": "workspace:*"
and"@hive/emails": "workspace:*"
supports the commerce functionalities introduced in this refactor. Confirm that these workspace packages are compatible and are used where necessary in the codebase.
21-21
: Introduction of Fastify as a Dependency
Replacing the removedgot
dependency with"fastify": "4.29.0"
is in line with performance enhancements expected from the new commerce service. Make sure that any related code changes (such as request handling) have been updated to accommodate Fastify if needed.integration-tests/package.json (1)
20-20
: Switch to Commerce Dependency
Replacing the deprecated@hive/rate-limit
with@hive/commerce
in the integration test dependencies is consistent with the overall service consolidation. Verify that all integration tests now target commerce-related endpoints and logic.packages/services/api/package.json (1)
67-67
: Addition of Stripe Package
The new dependency"stripe": "17.5.0"
has been introduced to support commerce-related billing operations. Please ensure that any Stripe integrations in the code are consistent with this version and function as expected within the consolidated service context.packages/services/server/.env.template (2)
17-17
: Addition of COMMERCE_ENDPOINT
The inclusion ofCOMMERCE_ENDPOINT="http://localhost:4013"
correctly points to the new commerce service endpoint. Confirm that this change is reflected in all related service configuration files and that documentation references are updated.
85-85
: Review HIVE_ENCRYPTION_SECRET Update
The update toHIVE_ENCRYPTION_SECRET=wowverysecuremuchsecret
should be verified to ensure it meets your security guidelines and remains consistent across environments. Consider whether this change is intended for all deployments and update relevant documentation if necessary.packages/services/commerce/README.md (1)
5-19
: Verify Configuration Table Completeness
The configuration table is comprehensive and clearly documents all relevant environment variables. Please double-check that the example values (such as those for Sentry, Prometheus, and OpenTelemetry) align with the intended deployment defaults.tsconfig.json (1)
61-61
: New TypeScript Path Mapping for Commerce
The new path mapping for@hive/commerce
pointing to./packages/services/commerce/src/api.ts
is correctly added. This update aligns with the consolidation of billing, rate-limit, and usage-estimator services into the unified commerce service.integration-tests/docker-compose.integration.yaml (1)
221-226
: Update Usage Service Environment
The injection ofCOMMERCE_ENDPOINT
into theusage
service’s environment is correctly done. Please verify that the actual endpoint passed via${COMMERCE_ENDPOINT}
in your .env file is consistent with the service’s deployment settings.docker/docker.hcl (1)
390-402
: Update Build Group With Commerce Target
Including thecommerce
target in both the build and integration-tests groups is correctly handled. This ensures that the new commerce service is integrated into the CI/CD pipeline alongside the other services.packages/services/server/README.md (1)
97-101
: Update Documentation for Commerce and CDN Settings
The new table rows introduce theCOMMERCE_ENDPOINT
—a required parameter replacing the legacy rate-limit/billing endpoints—which is clearly documented with an example value. Additionally, the added CDN configuration parameters (CDN_CF
andCDN_CF_BASE_URL
) are well formatted. Please double-check that the provided example values (e.g.http://127.0.0.1:4012
forCOMMERCE_ENDPOINT
) are consistent with the deployment configuration of the consolidated commerce service.
estimateOperationsForAllTargets: publicProcedure | ||
.input( | ||
z | ||
.object({ | ||
startTime: z.string().min(1), | ||
endTime: z.string().min(1), | ||
}) | ||
.required(), | ||
) | ||
.query(async ({ ctx, input }) => { | ||
return await ctx.usageEstimator.estimateOperationsForAllTargets({ | ||
startTime: new Date(input.startTime), | ||
endTime: new Date(input.endTime), | ||
}); | ||
}), |
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.
🛠️ Refactor suggestion
Add date range validation.
The input validation should ensure that startTime is before endTime.
.input(
z
.object({
startTime: z.string().min(1),
endTime: z.string().min(1),
- })
+ })
+ .refine(
+ (data) => new Date(data.startTime) < new Date(data.endTime),
+ 'Start time must be before end time'
+ )
.required(),
)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
estimateOperationsForAllTargets: publicProcedure | |
.input( | |
z | |
.object({ | |
startTime: z.string().min(1), | |
endTime: z.string().min(1), | |
}) | |
.required(), | |
) | |
.query(async ({ ctx, input }) => { | |
return await ctx.usageEstimator.estimateOperationsForAllTargets({ | |
startTime: new Date(input.startTime), | |
endTime: new Date(input.endTime), | |
}); | |
}), | |
estimateOperationsForAllTargets: publicProcedure | |
.input( | |
z | |
.object({ | |
startTime: z.string().min(1), | |
endTime: z.string().min(1), | |
}) | |
.refine( | |
(data) => new Date(data.startTime) < new Date(data.endTime), | |
'Start time must be before end time' | |
) | |
.required(), | |
) | |
.query(async ({ ctx, input }) => { | |
return await ctx.usageEstimator.estimateOperationsForAllTargets({ | |
startTime: new Date(input.startTime), | |
endTime: new Date(input.endTime), | |
}); | |
}), |
export const usageEstimatorRouter = router({ | ||
estimateOperationsForOrganization: publicProcedure | ||
.input( | ||
z | ||
.object({ | ||
month: z.number().min(1).max(12), | ||
year: z | ||
.number() | ||
.min(new Date().getFullYear() - 1) | ||
.max(new Date().getFullYear()), | ||
organizationId: z.string().min(1), | ||
}) | ||
.required(), | ||
) | ||
.query(async ({ ctx, input }) => { | ||
const estimationResponse = | ||
await ctx.usageEstimator.estimateCollectedOperationsForOrganization({ | ||
organizationId: input.organizationId, | ||
month: input.month, | ||
year: input.year, | ||
}); | ||
|
||
if (!estimationResponse.data.length) { | ||
return { | ||
totalOperations: 0, | ||
}; | ||
} | ||
|
||
return { | ||
totalOperations: parseInt(estimationResponse.data[0].total), | ||
}; | ||
}), |
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.
Add validation for total operations parsing.
The parseInt
call could fail if the total is not a valid number string.
- return {
- totalOperations: parseInt(estimationResponse.data[0].total),
- };
+ const totalOperations = parseInt(estimationResponse.data[0].total);
+ if (isNaN(totalOperations)) {
+ throw new Error('Invalid total operations value');
+ }
+ return { totalOperations };
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
export const usageEstimatorRouter = router({ | |
estimateOperationsForOrganization: publicProcedure | |
.input( | |
z | |
.object({ | |
month: z.number().min(1).max(12), | |
year: z | |
.number() | |
.min(new Date().getFullYear() - 1) | |
.max(new Date().getFullYear()), | |
organizationId: z.string().min(1), | |
}) | |
.required(), | |
) | |
.query(async ({ ctx, input }) => { | |
const estimationResponse = | |
await ctx.usageEstimator.estimateCollectedOperationsForOrganization({ | |
organizationId: input.organizationId, | |
month: input.month, | |
year: input.year, | |
}); | |
if (!estimationResponse.data.length) { | |
return { | |
totalOperations: 0, | |
}; | |
} | |
return { | |
totalOperations: parseInt(estimationResponse.data[0].total), | |
}; | |
}), | |
export const usageEstimatorRouter = router({ | |
estimateOperationsForOrganization: publicProcedure | |
.input( | |
z | |
.object({ | |
month: z.number().min(1).max(12), | |
year: z | |
.number() | |
.min(new Date().getFullYear() - 1) | |
.max(new Date().getFullYear()), | |
organizationId: z.string().min(1), | |
}) | |
.required(), | |
) | |
.query(async ({ ctx, input }) => { | |
const estimationResponse = | |
await ctx.usageEstimator.estimateCollectedOperationsForOrganization({ | |
organizationId: input.organizationId, | |
month: input.month, | |
year: input.year, | |
}); | |
if (!estimationResponse.data.length) { | |
return { | |
totalOperations: 0, | |
}; | |
} | |
const totalOperations = parseInt(estimationResponse.data[0].total); | |
if (isNaN(totalOperations)) { | |
throw new Error('Invalid total operations value'); | |
} | |
return { totalOperations }; | |
}), |
config.storage.connectionString, | ||
10, | ||
config.storage.additionalInterceptors, | ||
); | ||
const stripeApi = new Stripe(config.stripe.token, { | ||
apiVersion: '2024-12-18.acacia', |
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.
🛠️ Refactor suggestion
Avoid hardcoding the Stripe API version.
The hardcoded API version '2024-12-18.acacia'
could cause issues when Stripe releases new versions.
Consider:
- Moving the API version to configuration
- Using environment variables
- Adding validation to ensure the version exists
- apiVersion: '2024-12-18.acacia',
+ apiVersion: config.stripe.apiVersion,
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
apiVersion: '2024-12-18.acacia', | |
apiVersion: config.stripe.apiVersion, |
@@ -1,7 +1,9 @@ | |||
import 'reflect-metadata'; |
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.
🛠️ Refactor suggestion
Move reflect-metadata import to the application entry point.
The reflect-metadata
import should be at the application's entry point to ensure proper initialization of TypeScript decorators.
Move this import to your main application file (e.g., index.ts
or main.ts
).
const timeWindow = { | ||
startTime: startOfMonth(now), | ||
endTime: endOfMonth(now), | ||
}; |
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.
🛠️ Refactor suggestion
Avoid duplicate time window declaration.
The code declares the same time window object twice. The first declaration at lines 72-75 is unused.
- const window = {
- startTime: startOfMonth(now),
- endTime: endOfMonth(now),
- };
const timeWindow = {
startTime: startOfMonth(now),
endTime: endOfMonth(now),
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const timeWindow = { | |
startTime: startOfMonth(now), | |
endTime: endOfMonth(now), | |
}; | |
const timeWindow = { | |
startTime: startOfMonth(now), | |
endTime: endOfMonth(now), | |
}; |
PORT=4013 | ||
OPENTELEMETRY_COLLECTOR_ENDPOINT="<sync>" | ||
CLICKHOUSE_PROTOCOL="http" | ||
CLICKHOUSE_HOST="localhost" | ||
CLICKHOUSE_PORT="8123" | ||
CLICKHOUSE_USERNAME="test" | ||
CLICKHOUSE_PASSWORD="test" | ||
PORT=4011 | ||
POSTGRES_USER=postgres | ||
POSTGRES_PASSWORD=postgres | ||
POSTGRES_HOST=localhost | ||
POSTGRES_PORT=5432 | ||
POSTGRES_DB=registry | ||
OPENTELEMETRY_COLLECTOR_ENDPOINT="<sync>" No newline at end of file | ||
EMAILS_ENDPOINT="http://localhost:6260" | ||
WEB_APP_URL="http://localhost:3000" | ||
STRIPE_SECRET_KEY="empty" |
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.
💡 Verification agent
🧩 Analysis chain
Verify the README.md is updated with the new environment variables.
As per the coding guidelines for .env.template
files, ensure that the service's README.md
file includes documentation for all the new environment variables.
🏁 Script executed:
#!/bin/bash
# Description: Check if README.md exists and contains documentation for the new environment variables.
# Look for README.md in the commerce service directory
if [ -f "packages/services/commerce/README.md" ]; then
echo "Checking README.md for environment variables documentation..."
grep -A 5 "Environment Variables" "packages/services/commerce/README.md"
grep -E "EMAILS_ENDPOINT|WEB_APP_URL|STRIPE_SECRET_KEY" "packages/services/commerce/README.md"
else
echo "README.md not found in packages/services/commerce/"
fi
Length of output: 350
Action Required: Update README.md Documentation for New Environment Variables
It appears that the new environment variables—EMAILS_ENDPOINT, WEB_APP_URL, and STRIPE_SECRET_KEY—are currently not documented in the packages/services/commerce/README.md
file. Please update the README to include a dedicated section (or update an existing "Environment Variables" section) that describes these variables and their intended usage.
- Ensure the documentation clearly explains the purpose, expected values, and any defaults for:
EMAILS_ENDPOINT
WEB_APP_URL
STRIPE_SECRET_KEY
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: 1
🧹 Nitpick comments (2)
packages/services/api/src/modules/commerce/providers/billing.provider.ts (2)
33-33
: Update logger source name for consistency.The logger source name 'CommerceProvider' doesn't match the class name 'BillingProvider'. This might cause confusion when debugging.
- this.logger = logger.child({ source: 'CommerceProvider' }); + this.logger = logger.child({ source: 'BillingProvider' });
38-154
: Consider extracting common error handling logic.The client availability check is repeated across all methods. This could be extracted into a decorator or private method to reduce code duplication.
Example implementation:
private ensureClientAvailable() { if (!this.client) { throw new Error('Billing service is not configured!'); } }Then use it in each method:
async upgradeToPro(input: BillingInput['createSubscriptionForOrganization']) { this.logger.debug('Upgrading to PRO (input=%o)', input); - if (!this.client) { - throw new Error(`Billing service is not configured!`); - } + this.ensureClientAvailable(); // ... rest of the method }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/services/api/src/modules/commerce/providers/billing.provider.ts
(5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`packages/services/**`: Microservices written in NodeJS and ...
packages/services/**
: Microservices written in NodeJS and TypeScript. Most of the dirs under this directory are packages and deployed as Docker packages.
Interaction between services is done using tRPC.
We prefer writing code that does input/output validations with Zod.
The directories that ends with-worker
are projects that are built on top of CloudFlare Workers infrastructure and deployed there.
Thecdn-worker
is a special one, it serves a high-available, detached CDN on CloudFlare Workers. This is how our end-users fetches the crucial data from our platform, in a way that does not depend/couple on our main API (served as GraphQL API).
packages/services/api/src/modules/commerce/providers/billing.provider.ts
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: build / dockerize (linux/arm64)
- GitHub Check: build / dockerize (linux/amd64)
🔇 Additional comments (2)
packages/services/api/src/modules/commerce/providers/billing.provider.ts (2)
8-14
: LGTM! Clean import structure and type definitions.The new imports and type definitions align well with the service consolidation objectives, providing a clean abstraction for the commerce client integration.
16-19
: Review the scope configuration.The class is decorated with both
Scope.Operation
andglobal: true
. This combination seems contradictory as operation scope implies per-request instantiation while global scope suggests singleton behavior.Could you clarify the intended scoping behavior? If global behavior is needed, consider removing the operation scope.
throw new Error(`Billing service is not configured!`); | ||
} | ||
|
||
const result = this.billingService.createSubscriptionForOrganization.mutate(input); | ||
const result = this.client.stripeBilling.createSubscriptionForOrganization.mutate(input); |
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.
🛠️ Refactor suggestion
Add error handling for tRPC calls.
The tRPC client calls should include error handling to manage potential network issues or service failures.
Example implementation:
try {
return await this.client.stripeBilling.createSubscriptionForOrganization.mutate(input);
} catch (error) {
this.logger.error('Failed to create subscription', { error, input });
throw new Error('Failed to process billing operation');
}
Also applies to: 93-93, 102-102, 111-111, 129-129, 151-151
🐋 This PR was built and pushed to the following Docker images: Targets: Platforms: Image Tag: Docker Bake metadata{
"app": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/api/health",
"build-arg:IMAGE_DESCRIPTION": "The app of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/app",
"build-arg:PORT": "3000",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/app",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/w0k8qmxdf5vo09lp2qpw7lkpo",
"containerimage.config.digest": "sha256:08cf73a95666b725386c7feaac3778269ef650a8a74e0ee934f35b40b0ff6558",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:c00d568651466a3316f08a8d1ab3502f5a878bb0e51e266adc3f57fb77129c84",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:c00d568651466a3316f08a8d1ab3502f5a878bb0e51e266adc3f57fb77129c84",
"image.name": "ghcr.io/graphql-hive/app:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/app:kamil_commerce-arm64"
},
"buildx.build.warnings": [
{
"vertex": "sha256:b0f2b78074d57b28e06131ca9e104c49ccacd7a2342daa6bfa6069efbcfa9d20",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIxKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 21
},
"end": {
"line": 21
}
}
]
},
{
"vertex": "sha256:b0f2b78074d57b28e06131ca9e104c49ccacd7a2342daa6bfa6069efbcfa9d20",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRQT1JUJyAobGluZSAyMik=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 22
},
"end": {
"line": 22
}
}
]
},
{
"vertex": "sha256:c68e4914a3f0ecf97006930bde0ba7a92da285dbc43bcb0d701401bf31155242",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMik=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:c68e4914a3f0ecf97006930bde0ba7a92da285dbc43bcb0d701401bf31155242",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTUp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 15
},
"end": {
"line": 15
}
}
]
},
{
"vertex": "sha256:b0f2b78074d57b28e06131ca9e104c49ccacd7a2342daa6bfa6069efbcfa9d20",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAyMSk=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 21
},
"end": {
"line": 21
}
}
]
},
{
"vertex": "sha256:c68e4914a3f0ecf97006930bde0ba7a92da285dbc43bcb0d701401bf31155242",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEwKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 10
},
"end": {
"line": 10
}
}
]
},
{
"vertex": "sha256:b0f2b78074d57b28e06131ca9e104c49ccacd7a2342daa6bfa6069efbcfa9d20",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRSRUxFQVNFJyAobGluZSAxMyk=",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 13
},
"end": {
"line": 13
}
}
]
},
{
"vertex": "sha256:b0f2b78074d57b28e06131ca9e104c49ccacd7a2342daa6bfa6069efbcfa9d20",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIyKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 22
},
"end": {
"line": 22
}
}
]
},
{
"vertex": "sha256:c68e4914a3f0ecf97006930bde0ba7a92da285dbc43bcb0d701401bf31155242",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDExKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 11
},
"end": {
"line": 11
}
}
]
},
{
"vertex": "sha256:b0f2b78074d57b28e06131ca9e104c49ccacd7a2342daa6bfa6069efbcfa9d20",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDIwKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 20
},
"end": {
"line": 20
}
}
]
},
{
"vertex": "sha256:b0f2b78074d57b28e06131ca9e104c49ccacd7a2342daa6bfa6069efbcfa9d20",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTQp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 14
},
"end": {
"line": 14
}
}
]
},
{
"vertex": "sha256:c68e4914a3f0ecf97006930bde0ba7a92da285dbc43bcb0d701401bf31155242",
"level": 1,
"short": "TGVnYWN5S2V5VmFsdWVGb3JtYXQ6ICJFTlYga2V5PXZhbHVlIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkIG9mIGxlZ2FjeSAiRU5WIGtleSB2YWx1ZSIgZm9ybWF0IChsaW5lIDEyKQ==",
"detail": [
"TGVnYWN5IGtleS92YWx1ZSBmb3JtYXQgd2l0aCB3aGl0ZXNwYWNlIHNlcGFyYXRvciBzaG91bGQgbm90IGJlIHVzZWQ="
],
"url": "https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
},
{
"vertex": "sha256:c68e4914a3f0ecf97006930bde0ba7a92da285dbc43bcb0d701401bf31155242",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9ERVNDUklQVElPTicgKGxpbmUgMTcp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "migrations.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSBjYS1jZXJ0aWZpY2F0ZXMKCldPUktESVIgL3Vzci9zcmMvYXBwCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpFTlYgRU5WSVJPTk1FTlQgcHJvZHVjdGlvbgpFTlYgTk9ERV9FTlYgcHJvZHVjdGlvbgpFTlYgUkVMRUFTRSAkUkVMRUFTRQoKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmxpY2Vuc2VzPU1JVApMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudGl0bGU9JElNQUdFX1RJVExFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS52ZXJzaW9uPSRSRUxFQVNFCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS5kZXNjcmlwdGlvbj0kSU1BR0VfREVTQ1JJUFRJT04KTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmF1dGhvcnM9IlRoZSBHdWlsZCIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlbmRvcj0iS2FtaWwgS2lzaWVsYSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnVybD0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnNvdXJjZT0iaHR0cHM6Ly9naXRodWIuY29tL2dyYXBocWwtaGl2ZS9wbGF0Zm9ybSIKCkVOVFJZUE9JTlQgWyAiL2VudHJ5cG9pbnQuc2giIF0K",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 17
},
"end": {
"line": 17
}
}
]
},
{
"vertex": "sha256:b0f2b78074d57b28e06131ca9e104c49ccacd7a2342daa6bfa6069efbcfa9d20",
"level": 1,
"short": "VW5kZWZpbmVkVmFyOiBVc2FnZSBvZiB1bmRlZmluZWQgdmFyaWFibGUgJyRJTUFHRV9USVRMRScgKGxpbmUgMTIp",
"detail": [
"VmFyaWFibGVzIHNob3VsZCBiZSBkZWZpbmVkIGJlZm9yZSB0aGVpciB1c2U="
],
"url": "https://docs.docker.com/go/dockerfile/rule/undefined-var/",
"sourceInfo": {
"filename": "services.dockerfile",
"data": "RlJPTSBub2RlOjIyLjEzLjAtc2xpbQoKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSB3Z2V0IGNhLWNlcnRpZmljYXRlcyAmJiBybSAtcmYgL3Zhci9saWIvYXB0L2xpc3RzLyoKCkFSRyBTRVJWSUNFX0RJUl9OQU1FCldPUktESVIgL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FCgpDT1BZIC0tZnJvbT1kaXN0IC4gL3Vzci9zcmMvYXBwLyRTRVJWSUNFX0RJUl9OQU1FLwpDT1BZIC0tZnJvbT1zaGFyZWQgLiAvCgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UubGljZW5zZXM9TUlUCkxBQkVMIG9yZy5vcGVuY29udGFpbmVycy5pbWFnZS50aXRsZT0kSU1BR0VfVElUTEUKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLnZlcnNpb249JFJFTEVBU0UKTEFCRUwgb3JnLm9wZW5jb250YWluZXJzLmltYWdlLmRlc2NyaXB0aW9uPSRJTUFHRV9ERVNDUklQVElPTgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UuYXV0aG9ycz0iVGhlIEd1aWxkIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudmVuZG9yPSJLYW1pbCBLaXNpZWxhIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2UudXJsPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgpMQUJFTCBvcmcub3BlbmNvbnRhaW5lcnMuaW1hZ2Uuc291cmNlPSJodHRwczovL2dpdGh1Yi5jb20vZ3JhcGhxbC1oaXZlL3BsYXRmb3JtIgoKRU5WIEVOVklST05NRU5UIHByb2R1Y3Rpb24KRU5WIFJFTEVBU0UgJFJFTEVBU0UKRU5WIFBPUlQgJFBPUlQKCkhFQUxUSENIRUNLIC0taW50ZXJ2YWw9NXMgXAogIC0tdGltZW91dD01cyBcCiAgLS1zdGFydC1wZXJpb2Q9NXMgXAogIC0tcmV0cmllcz02IFwKICBDTUQgJEhFQUxUSENIRUNLX0NNRAoKRU5UUllQT0lOVCBbICIvZW50cnlwb2ludC5zaCIgXQo=",
"language": "Dockerfile"
},
"range": [
{
"start": {
"line": 12
},
"end": {
"line": 12
}
}
]
}
],
"commerce": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The commerce service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/commerce",
"build-arg:PORT": "3010",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/commerce",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/zjz5hcv07c6jqcua5dhm4ucdx",
"containerimage.config.digest": "sha256:b3bc070498acb1bcbe7a9932b775a6ae5c20de53a80df3846a98f56fd601a98a",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:9040c5610ac3d9b333fe06fe345ce477fbdc884beedddbad2d1d88d5ca87d258",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:9040c5610ac3d9b333fe06fe345ce477fbdc884beedddbad2d1d88d5ca87d258",
"image.name": "ghcr.io/graphql-hive/commerce:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/commerce:kamil_commerce-arm64"
},
"composition-federation-2": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "Federation 2 Composition Service for GraphQL Hive.",
"build-arg:IMAGE_TITLE": "graphql-hive/composition-federation-2",
"build-arg:PORT": "3069",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/external-composition",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/helvr33k939kcpyi38wxxe39g",
"containerimage.config.digest": "sha256:4d51f801c62f8d781d2d210dcfe4df79c7d291be1259adf7ef3f05ae9f2f8791",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:0c36546f54e71075b4c1632ddc5e5aee79fc44ea33da26d75177c80898b38566",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:0c36546f54e71075b4c1632ddc5e5aee79fc44ea33da26d75177c80898b38566",
"image.name": "ghcr.io/graphql-hive/composition-federation-2:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/composition-federation-2:kamil_commerce-arm64"
},
"emails": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The emails service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/emails",
"build-arg:PORT": "3006",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/emails",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/su9bwzujrhfcaojdi72t00jqg",
"containerimage.config.digest": "sha256:cfe7b7b1c822959a3fcbfe803e2d58fa8a949a3c6b04f7aae0649725ca1e1dda",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:ab8c94f37eab6e2c80eaa500ac8c7950a8a14eded0116602bd4344ad9c2e3c60",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:ab8c94f37eab6e2c80eaa500ac8c7950a8a14eded0116602bd4344ad9c2e3c60",
"image.name": "ghcr.io/graphql-hive/emails:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/emails:kamil_commerce-arm64"
},
"policy": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The policy service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/policy",
"build-arg:PORT": "3012",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/policy",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/ak54q1oieram56pukeiwd1v75",
"containerimage.config.digest": "sha256:177c0fa3167557179b30537327f0a4770b60749fed2ad9bb1eca99ce5fd46f13",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:bba9d28ec9fe3d334706e22e473c873b590237dc6d9211ad22f68dd0e9b2ae71",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:bba9d28ec9fe3d334706e22e473c873b590237dc6d9211ad22f68dd0e9b2ae71",
"image.name": "ghcr.io/graphql-hive/policy:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/policy:kamil_commerce-arm64"
},
"schema": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The schema service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/schema",
"build-arg:PORT": "3002",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/schema",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/3ct9wnv8dyylxl3awzrr146sm",
"containerimage.config.digest": "sha256:87a7eb148c9d2908a6b771491c9f8905b9a9a517f64477c6799f25ac74b3aa02",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:4cf53cf1fe8be90a65000e341cb4fe9540fcce3a9a4cf1a0d3f13599acb90faf",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:4cf53cf1fe8be90a65000e341cb4fe9540fcce3a9a4cf1a0d3f13599acb90faf",
"image.name": "ghcr.io/graphql-hive/schema:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/schema:kamil_commerce-arm64"
},
"server": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The server service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/server",
"build-arg:PORT": "3001",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/server",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/meq55vzferglesu569811244z",
"containerimage.config.digest": "sha256:ae61b5d70806c6a4dc132a1291de980fea5d5e31dbda923eb8ee1facd1a8ed46",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:a59eec791b35d3939e5492166cde95c6b50f661624ef282fae3c6eccf8b99c55",
"size": 2076,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:a59eec791b35d3939e5492166cde95c6b50f661624ef282fae3c6eccf8b99c55",
"image.name": "ghcr.io/graphql-hive/server:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/server:kamil_commerce-arm64"
},
"storage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "migrations.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:IMAGE_DESCRIPTION": "The migrations service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/storage",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/uk4sqegp6nhqhr9vkw6whuq9w",
"containerimage.config.digest": "sha256:0deb7f18a1cae1a2b5791faf05ba468a200bd7788b4dce4eef9b4e06839b3a09",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:31131e99260dbdf442d257584fab0aae519ec81ea300e40b9ec7600a10fb235d",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:31131e99260dbdf442d257584fab0aae519ec81ea300e40b9ec7600a10fb235d",
"image.name": "ghcr.io/graphql-hive/storage:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/storage:kamil_commerce-arm64"
},
"tokens": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The tokens service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/tokens",
"build-arg:PORT": "3003",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/tokens",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/ntw13uroiukeqdzpvdfwge92k",
"containerimage.config.digest": "sha256:206d1f28a1aa4820a6924473516cb5fdd9bb495b3cadf707e8564815067e897f",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:f8593f2ea7f374be75a4fc54aa1778f86c2a74dd28612bb09635c14bcb72b56b",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:f8593f2ea7f374be75a4fc54aa1778f86c2a74dd28612bb09635c14bcb72b56b",
"image.name": "ghcr.io/graphql-hive/tokens:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/tokens:kamil_commerce-arm64"
},
"usage": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/usage",
"build-arg:PORT": "3006",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/usage",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/ledhzo928zkzfj5hky5e7mj9z",
"containerimage.config.digest": "sha256:a738f36f4f45681390784d2e483c37415bad0cb7869484fa5f79c95aba6fa2bf",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:7b84d90ae10ff986938cae73e8226482b0414956b379e32f2b679ed5012ce777",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:7b84d90ae10ff986938cae73e8226482b0414956b379e32f2b679ed5012ce777",
"image.name": "ghcr.io/graphql-hive/usage:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/usage:kamil_commerce-arm64"
},
"usage-ingestor": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The usage ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/usage-ingestor",
"build-arg:PORT": "3007",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/usage-ingestor",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/nlq0k759gmzjwokaa3ap970ly",
"containerimage.config.digest": "sha256:627e07a6dcc5824459ce71fa230064c06cc8448151c500757f261711b6525d68",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:7996d55162b09a0b386834e6d6ca691e1a46cc18239ab9e5f62efc61283caa37",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:7996d55162b09a0b386834e6d6ca691e1a46cc18239ab9e5f62efc61283caa37",
"image.name": "ghcr.io/graphql-hive/usage-ingestor:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/usage-ingestor:kamil_commerce-arm64"
},
"webhooks": {
"buildx.build.provenance": {
"buildType": "https://mobyproject.org/buildkit@v1",
"materials": [
{
"uri": "pkg:docker/[email protected]?platform=linux%2Farm64",
"digest": {
"sha256": "f5a0871ab03b035c58bdb3007c3d177b001c2145c18e81817b71624dcf7d8bff"
}
}
],
"invocation": {
"configSource": {
"entryPoint": "services.dockerfile"
},
"parameters": {
"frontend": "dockerfile.v0",
"args": {
"build-arg:HEALTHCHECK_CMD": "wget --spider -q http://127.0.0.1:${PORT}/_readiness",
"build-arg:IMAGE_DESCRIPTION": "The webhooks ingestor service of the GraphQL Hive project.",
"build-arg:IMAGE_TITLE": "graphql-hive/webhooks",
"build-arg:PORT": "3005",
"build-arg:RELEASE": "76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9",
"build-arg:SERVICE_DIR_NAME": "@hive/webhooks",
"context:dist": "local:dist",
"context:shared": "local:shared",
"frontend.caps": "moby.buildkit.frontend.contexts+forward",
"local-sessionid:context": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:dockerfile": "klwtftj083jdt2kg99wpgnxqm",
"local-sessionid:shared": "klwtftj083jdt2kg99wpgnxqm"
},
"locals": [
{
"name": "context"
},
{
"name": "dist"
},
{
"name": "dockerfile"
},
{
"name": "shared"
}
]
},
"environment": {
"platform": "linux/arm64"
}
}
},
"buildx.build.ref": "builder-f3022c26-2c8b-4b83-bcb4-13261ae864b9/builder-f3022c26-2c8b-4b83-bcb4-13261ae864b90/s5xc6e0omy6mduo41i95089pt",
"containerimage.config.digest": "sha256:fb839ccbe7378a29984b76cdbdae743b90f1d2a456ea40b00dd524b505747b29",
"containerimage.descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:0a0a0bc63e41d4090bcf9993cd2a612b43809d88812c91a3b9ffd612324cb652",
"size": 2075,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
"containerimage.digest": "sha256:0a0a0bc63e41d4090bcf9993cd2a612b43809d88812c91a3b9ffd612324cb652",
"image.name": "ghcr.io/graphql-hive/webhooks:76a4f1cff59e73dcb829a7f4a37e6c47bbd898e9-arm64,ghcr.io/graphql-hive/webhooks:kamil_commerce-arm64"
}
} |
import { createTRPCProxyClient, httpLink } from '@trpc/client'; | ||
import type { RateLimitInput } from './api'; | ||
import { UsageEstimator } from '../usage-estimator/estimator'; | ||
// import type { RateLimitInput } from './api'; |
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.
remove comment
@@ -10,7 +10,6 @@ The GraphQL API for GraphQL Hive. | |||
| `ENCRYPTION_SECRET` | **Yes** | Secret for encrypting stuff. | `8ebe95cg21c1fee355e9fa32c8c33141` | | |||
| `WEB_APP_URL` | **Yes** | The url of the web app. | `http://127.0.0.1:3000` | | |||
| `GRAPHQL_PUBLIC_ORIGIN` | **Yes** | The origin of the GraphQL server. | `http://127.0.0.1:4013` | | |||
| `RATE_LIMIT_ENDPOINT` | **Yes** | The endpoint of the rate limiting service. | `http://127.0.0.1:4012` | |
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.
Should this be replaced by one for the COMMERCE_ENDPOINT
?
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.
It's in the Hive Cloud Configuration
below
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.
In general this architectural change makes a lot of sense. There are a lot of details in this PR though.
And is there a migration plan or are we comfortable taking downtime?
The only downtime (1) here could be stripe-billing / usage-estimator related. Very unlikely that somebody will make a request that involves one of them. I think the downtime (1) is fine, otherwise we would have to do a 2 step rollout with 2 services running at the same time, not sure it's worth the hassle. |
The
rate-limit
,stripe-billing
andusage-estimator
services are specific to Hive Cloud.I'm merging them into one, called
commerce
.I also merged
billing
,rate-limit
andusage-estimator
modules (in@hive/api
) intocommerce
.Everything stayed almost identical.
Closes CONSOLE-1083