d25d482dc2
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
89 lines
3.3 KiB
TypeScript
89 lines
3.3 KiB
TypeScript
/**
|
|
* Upgrade-reason registry.
|
|
*
|
|
* Single source of truth for the language shown when a user is routed to the
|
|
* upgrade page after hitting a usage limit. The same copy drives both the
|
|
* upgrade-page header and the threshold/limit emails, so the in-app and email
|
|
* journeys never drift apart.
|
|
*/
|
|
|
|
/** The limit categories that can route a user to the upgrade page. */
|
|
export const UPGRADE_REASONS = ['credits', 'storage', 'tables', 'seats'] as const
|
|
|
|
export type UpgradeReason = (typeof UPGRADE_REASONS)[number]
|
|
|
|
/** URL query key the upgrade page reads to resolve the reason. */
|
|
export const UPGRADE_REASON_PARAM = 'reason' as const
|
|
|
|
/** Header shown on the upgrade page when no (or an invalid) reason is present. */
|
|
export const DEFAULT_UPGRADE_HEADER = 'Plans that scale with you' as const
|
|
|
|
interface UpgradeReasonCopy {
|
|
/** Upgrade-page `<h1>` header. */
|
|
header: string
|
|
/** Lowercase noun for the limited resource (e.g. "tables", "storage"). */
|
|
noun: string
|
|
/** Subject line for the 80% warning email. */
|
|
warningSubject: string
|
|
/** Subject line for the 100% limit-reached email. */
|
|
reachedSubject: string
|
|
/** One-line body lead for the warning email (running low). */
|
|
warningLead: string
|
|
/** One-line body lead for the limit-reached email. */
|
|
reachedLead: string
|
|
}
|
|
|
|
/**
|
|
* Per-reason copy. Headers follow the "Upgrade to scale ..." pattern; email
|
|
* subjects/leads reuse the same noun so a user sees consistent language whether
|
|
* they arrive from the app or from an email.
|
|
*/
|
|
export const UPGRADE_REASON_COPY: Record<UpgradeReason, UpgradeReasonCopy> = {
|
|
credits: {
|
|
header: 'Upgrade to scale your usage',
|
|
noun: 'credits',
|
|
warningSubject: "You're nearing your usage limit",
|
|
reachedSubject: "You've reached your usage limit",
|
|
warningLead: "You're approaching your usage limit.",
|
|
reachedLead: "You've reached your usage limit.",
|
|
},
|
|
storage: {
|
|
header: 'Upgrade to scale your storage',
|
|
noun: 'storage',
|
|
warningSubject: "You're running low on storage",
|
|
reachedSubject: "You've reached your storage limit",
|
|
warningLead: "You're running low on storage.",
|
|
reachedLead: "You've reached your storage limit.",
|
|
},
|
|
tables: {
|
|
header: 'Upgrade to scale your tables',
|
|
noun: 'table rows',
|
|
warningSubject: "You're running low on table space",
|
|
reachedSubject: "You've reached your table limit",
|
|
warningLead: "You're running low on table space.",
|
|
reachedLead: "You've reached your table limit.",
|
|
},
|
|
seats: {
|
|
header: 'Upgrade to scale with your teammates',
|
|
noun: 'seats',
|
|
warningSubject: "You're running low on seats",
|
|
reachedSubject: "You've used all your seats",
|
|
warningLead: "You're running low on seats for your team.",
|
|
reachedLead: "You've used all the seats on your plan.",
|
|
},
|
|
}
|
|
|
|
/** Type guard for a raw query value against the known reasons. */
|
|
export function isUpgradeReason(value: string | null | undefined): value is UpgradeReason {
|
|
return value != null && (UPGRADE_REASONS as readonly string[]).includes(value)
|
|
}
|
|
|
|
/**
|
|
* Build a link to the workspace upgrade page, optionally tagged with the reason
|
|
* that sent the user there so the page can swap its header.
|
|
*/
|
|
export function buildUpgradeHref(workspaceId: string, reason?: UpgradeReason): string {
|
|
const base = `/workspace/${workspaceId}/upgrade`
|
|
return reason ? `${base}?${UPGRADE_REASON_PARAM}=${reason}` : base
|
|
}
|