Skip to content

Commit f3ddb35

Browse files
committed
improvement(env): extract envNumber helper for numeric env coercion
1 parent 81f35c9 commit f3ddb35

5 files changed

Lines changed: 27 additions & 31 deletions

File tree

apps/sim/lib/billing/subscriptions/utils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
isTeam,
1515
} from '@/lib/billing/plan-helpers'
1616
import { parseEnterpriseSubscriptionMetadata } from '@/lib/billing/types'
17-
import { env } from '@/lib/core/config/env'
17+
import { env, envNumber } from '@/lib/core/config/env'
1818

1919
export const ENTITLED_SUBSCRIPTION_STATUSES = ['active', 'past_due'] as const
2020

@@ -52,28 +52,28 @@ export function hasUsableSubscriptionAccess(
5252
* Get the free tier limit from env or fallback to default
5353
*/
5454
export function getFreeTierLimit(): number {
55-
return env.FREE_TIER_COST_LIMIT || DEFAULT_FREE_CREDITS
55+
return envNumber(env.FREE_TIER_COST_LIMIT, DEFAULT_FREE_CREDITS)
5656
}
5757

5858
/**
5959
* Get the pro tier limit from env or fallback to default
6060
*/
6161
export function getProTierLimit(): number {
62-
return env.PRO_TIER_COST_LIMIT || DEFAULT_PRO_TIER_COST_LIMIT
62+
return envNumber(env.PRO_TIER_COST_LIMIT, DEFAULT_PRO_TIER_COST_LIMIT)
6363
}
6464

6565
/**
6666
* Get the team tier limit per seat from env or fallback to default
6767
*/
6868
export function getTeamTierLimitPerSeat(): number {
69-
return env.TEAM_TIER_COST_LIMIT || DEFAULT_TEAM_TIER_COST_LIMIT
69+
return envNumber(env.TEAM_TIER_COST_LIMIT, DEFAULT_TEAM_TIER_COST_LIMIT)
7070
}
7171

7272
/**
7373
* Get the enterprise tier limit per seat from env or fallback to default
7474
*/
7575
export function getEnterpriseTierLimitPerSeat(): number {
76-
return env.ENTERPRISE_TIER_COST_LIMIT || DEFAULT_ENTERPRISE_TIER_COST_LIMIT
76+
return envNumber(env.ENTERPRISE_TIER_COST_LIMIT, DEFAULT_ENTERPRISE_TIER_COST_LIMIT)
7777
}
7878

7979
export function checkEnterprisePlan(subscription: any): boolean {

apps/sim/lib/billing/threshold-billing.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ import {
1616
} from '@/lib/billing/subscriptions/utils'
1717
import { toDecimal, toNumber } from '@/lib/billing/utils/decimal'
1818
import { OUTBOX_EVENT_TYPES } from '@/lib/billing/webhooks/outbox-handlers'
19-
import { env } from '@/lib/core/config/env'
19+
import { env, envNumber } from '@/lib/core/config/env'
2020
import { enqueueOutboxEvent } from '@/lib/core/outbox/service'
2121

2222
const logger = createLogger('ThresholdBilling')
2323

24-
const OVERAGE_THRESHOLD = env.OVERAGE_THRESHOLD_DOLLARS || DEFAULT_OVERAGE_THRESHOLD
24+
const OVERAGE_THRESHOLD = envNumber(env.OVERAGE_THRESHOLD_DOLLARS, DEFAULT_OVERAGE_THRESHOLD)
2525

2626
export async function checkAndBillOverageThreshold(userId: string): Promise<void> {
2727
try {

apps/sim/lib/copilot/request/session/buffer.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { createLogger } from '@sim/logger'
22
import { toError } from '@sim/utils/errors'
33
import { sleep } from '@sim/utils/helpers'
4-
import { env } from '@/lib/core/config/env'
4+
import { env, envNumber } from '@/lib/core/config/env'
55
import { getRedisClient } from '@/lib/core/config/redis'
66
import {
77
type PersistedStreamEventEnvelope,
@@ -40,19 +40,11 @@ export type StreamConfig = {
4040

4141
export function getStreamConfig(): StreamConfig {
4242
return {
43-
ttlSeconds: parsePositiveNumber(env.COPILOT_STREAM_TTL_SECONDS, DEFAULT_TTL_SECONDS),
44-
eventLimit: parsePositiveNumber(env.COPILOT_STREAM_EVENT_LIMIT, DEFAULT_EVENT_LIMIT),
43+
ttlSeconds: envNumber(env.COPILOT_STREAM_TTL_SECONDS, DEFAULT_TTL_SECONDS),
44+
eventLimit: envNumber(env.COPILOT_STREAM_EVENT_LIMIT, DEFAULT_EVENT_LIMIT),
4545
}
4646
}
4747

48-
function parsePositiveNumber(value: number | string | undefined, fallback: number) {
49-
if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
50-
return value
51-
}
52-
const parsed = Number(value)
53-
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback
54-
}
55-
5648
async function withRedisRetry<T>(
5749
metadata: RedisOperationMetadata,
5850
operation: (redis: NonNullable<ReturnType<typeof getRedisClient>>) => Promise<T>

apps/sim/lib/core/config/env.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,3 +514,19 @@ export const isFalsy = (value: string | boolean | number | undefined) =>
514514
typeof value === 'string' ? value.toLowerCase() === 'false' || value === '0' : value === false
515515

516516
export { getEnv }
517+
518+
/**
519+
* Coerce an env-derived value to a positive finite number, falling back to the
520+
* provided default when the value is unset, empty, non-finite, or ≤ 0.
521+
*
522+
* `createEnv` is configured with `skipValidation: true`, so values declared as
523+
* `z.number()` arrive as raw strings when sourced from `process.env` or Helm.
524+
* Use this helper anywhere a numeric env override is consumed to normalize the
525+
* type at the boundary instead of relying on JS implicit coercion.
526+
*/
527+
export function envNumber(value: number | string | undefined | null, fallback: number): number {
528+
if (typeof value === 'number' && Number.isFinite(value) && value > 0) return value
529+
if (value === undefined || value === null || value === '') return fallback
530+
const parsed = Number(value)
531+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback
532+
}

apps/sim/lib/table/constants.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Limits and constants for user-defined tables.
33
*/
44

5-
import { env } from '@/lib/core/config/env'
5+
import { env, envNumber } from '@/lib/core/config/env'
66

77
export const TABLE_LIMITS = {
88
MAX_TABLES_PER_WORKSPACE: 100,
@@ -58,18 +58,6 @@ export interface TablePlanLimits {
5858

5959
export type TablePlanLimitsByPlan = Record<PlanName, TablePlanLimits>
6060

61-
/**
62-
* Coerce an env value to a number. `env.ts` runs with `skipValidation: true`,
63-
* so values declared as `z.number()` arrive as raw strings (e.g. when set via
64-
* Helm). Falls back to the default when the value is unset, empty, or not a
65-
* finite number.
66-
*/
67-
function envNumber(value: number | string | undefined, fallback: number): number {
68-
if (value === undefined || value === null || value === '') return fallback
69-
const parsed = typeof value === 'number' ? value : Number(value)
70-
return Number.isFinite(parsed) ? parsed : fallback
71-
}
72-
7361
/**
7462
* Returns plan-based table limits, applying env var overrides on top of the
7563
* defaults. When no override is set the value falls back to the hosted-default

0 commit comments

Comments
 (0)