Skip to content
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

feat: add refill option 'never' in case you dont ever want to refil the number of uses #2780

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/api/src/pkg/key_migration/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type MessageBody = {
permissions?: string[];
expires?: number;
remaining?: number;
refill?: { interval: "daily" | "monthly"; amount: number; refillDay?: number };
refill?: { interval: "daily" | "monthly" | "never"; amount: number; refillDay?: number };
ratelimit?: { async: boolean; limit: number; duration: number };
enabled: boolean;
environment?: string;
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/routes/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const keySchema = z
}),
refill: z
.object({
interval: z.enum(["daily", "monthly"]).openapi({
interval: z.enum(["daily", "monthly", "never"]).openapi({
description:
"Determines the rate at which verifications will be refilled. When 'daily' is set for 'interval' 'refillDay' will be set to null.",
example: "daily",
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/routes/v1_keys_createKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,10 @@ When validating a key, we will return this back to you, so you can clearly ident
}),
refill: z
.object({
interval: z.enum(["daily", "monthly"]).openapi({
interval: z.enum(["daily", "monthly", "never"]).openapi({
description: "Unkey will automatically refill verifications at the set interval.",
}),
amount: z.number().int().min(1).positive().openapi({
amount: z.number().int().min(0).openapi({
description:
"The number of verifications to refill for each occurrence is determined individually for each key.",
}),
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/routes/v1_keys_updateKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,11 @@ This field will become required in a future version.`,
}),
refill: z
.object({
interval: z.enum(["daily", "monthly"]).openapi({
interval: z.enum(["daily", "monthly", "never"]).openapi({
description:
"Unkey will automatically refill verifications at the set interval. If null is used the refill functionality will be removed from the key.",
}),
amount: z.number().int().min(1).openapi({
amount: z.number().int().min(0).openapi({
description:
"The amount of verifications to refill for each occurrence is determined individually for each key.",
}),
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/routes/v1_migrations_createKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@ When validating a key, we will return this back to you, so you can clearly ident
}),
refill: z
.object({
interval: z.enum(["daily", "monthly"]).openapi({
interval: z.enum(["daily", "monthly", "never"]).openapi({
description:
"Unkey will automatically refill verifications at the set interval.",
}),
amount: z.number().int().min(1).positive().openapi({
amount: z.number().int().min(0).openapi({
description:
"The number of verifications to refill for each occurrence is determined individually for each key.",
}),
Expand Down
4 changes: 2 additions & 2 deletions apps/api/src/routes/v1_migrations_enqueueKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,11 @@ When validating a key, we will return this back to you, so you can clearly ident
}),
refill: z
.object({
interval: z.enum(["daily", "monthly"]).openapi({
interval: z.enum(["daily", "monthly", "never"]).openapi({
description:
"Unkey will automatically refill verifications at the set interval.",
}),
amount: z.number().int().min(1).positive().openapi({
amount: z.number().int().min(0).openapi({
description:
"The number of verifications to refill for each occurrence is determined individually for each key.",
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,13 @@ const formSchema = z.object({
remaining: z.coerce.number().positive({ message: "Please enter a positive number" }).optional(),
refill: z
.object({
interval: z.enum(["none", "daily", "monthly"]),
interval: z.enum(["none", "daily", "monthly", "never"]),
amount: z.coerce
.number()
.int()
.min(1, {
.min(0, {
message: "Please enter the number of uses per interval",
})
.positive()
.optional(),
refillDay: z.coerce
.number({
Expand All @@ -72,7 +71,7 @@ type Props = {
id: string;
workspaceId: string;
remaining: number | null;
refillInterval: "daily" | "monthly" | null;
refillInterval: "daily" | "monthly" | "never" | null;
refillAmount: number | null;
refillDay: number | null;
};
Expand Down Expand Up @@ -196,6 +195,7 @@ export const UpdateKeyRemaining: React.FC<Props> = ({ apiKey }) => {
<SelectItem value="none">None</SelectItem>
<SelectItem value="daily">Daily</SelectItem>
<SelectItem value="monthly">Monthly</SelectItem>
<SelectItem value="never">Never</SelectItem>
</SelectContent>
</Select>
<FormMessage />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,11 @@ export const CreateKey = ({ apiId, keyAuthId, defaultBytes, defaultPrefix }: Pro
if (!values.ratelimitEnabled) {
delete values.ratelimit;
}
const refill = values.limit?.refill;
const refill = values.limit?.refill
? { ...values.limit.refill, amount: values.limit.refill.amount ?? 0 }
: undefined;
if (refill?.interval === "daily") {
refill?.refillDay === undefined;
refill.refillDay === undefined;
}
if (refill?.interval === "monthly" && !refill.refillDay) {
refill.refillDay = 1;
Expand Down Expand Up @@ -510,6 +512,7 @@ export const CreateKey = ({ apiId, keyAuthId, defaultBytes, defaultPrefix }: Pro
<SelectContent>
<SelectItem value="daily">Daily</SelectItem>
<SelectItem value="monthly">Monthly</SelectItem>
<SelectItem value="never">Never</SelectItem>
</SelectContent>
</Select>
<FormDescription>
Expand All @@ -520,6 +523,7 @@ export const CreateKey = ({ apiId, keyAuthId, defaultBytes, defaultPrefix }: Pro
/>
<FormField
control={form.control}
disabled={form.watch("limit.refill.interval") === "never"}
name="limit.refill.amount"
render={({ field }) => (
<FormItem className="mt-4">
Expand All @@ -531,7 +535,7 @@ export const CreateKey = ({ apiId, keyAuthId, defaultBytes, defaultPrefix }: Pro
type="number"
{...field}
value={
form.getValues("limitEnabled") ? field.value : undefined
form.getValues("limitEnabled") ? field.value : 0
}
/>
</FormControl>
Expand All @@ -547,7 +551,8 @@ export const CreateKey = ({ apiId, keyAuthId, defaultBytes, defaultPrefix }: Pro
control={form.control}
disabled={
form.watch("limit.refill.amount") === undefined ||
form.watch("limit.refill.interval") === "daily"
form.watch("limit.refill.interval") === "daily" ||
form.watch("limit.refill.interval") === "never"
}
name="limit.refill.refillDay"
render={({ field }) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const formSchema = z.object({
.positive({ message: "Please enter a positive number" }),
refill: z
.object({
interval: z.enum(["daily", "monthly"]).default("monthly"),
interval: z.enum(["daily", "monthly", "never"]).default("monthly"),
amount: z.coerce
.number({
errorMap: (issue, { defaultError }) => ({
Expand All @@ -62,8 +62,8 @@ export const formSchema = z.object({
}),
})
.int()
.min(1)
.positive(),
.min(0)
.optional(),
refillDay: z.coerce
.number({
errorMap: (issue, { defaultError }) => ({
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/lib/trpc/routers/key/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ export const createKey = t.procedure
remaining: z.number().int().positive().optional(),
refill: z
.object({
interval: z.enum(["daily", "monthly"]),
amount: z.coerce.number().int().min(1),
interval: z.enum(["daily", "monthly", "never"]),
amount: z.coerce.number().int().min(0),
Comment on lines +21 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Based on the code analysis, I can now generate the final response:

Zero refill amounts are not allowed for daily/monthly intervals

The codebase enforces validation that prevents setting a refill amount to zero when using daily or monthly intervals:

  • In apps/dashboard/lib/trpc/routers/key/create.ts, the schema validation requires amount: z.coerce.number().int().min(0) but additional checks are present in the codebase:
  • In apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/settings/update-key-remaining.tsx, there's explicit validation:
    if (values.refill?.interval !== "none" && !values.refill?.amount) {
      form.setError("refill.amount", {
        message: "Please enter the number of uses per interval",
      });
      return;
    }
  • The API routes in apps/api/src/routes/v1_keys_createKey.ts and related files also enforce that refill amounts must be provided when using intervals.
🔗 Analysis chain

Allowing zero refill amounts for “never”
Permitting a minimum value of 0 is consistent with “never” refills. Verify that logic remains sound for daily/monthly intervals if a user attempts to set the amount to zero.


Let me gather more information about how the refill amount is handled for different intervals.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for usage of interval and amount in the codebase
rg -A 10 "interval.*amount" --type ts

Length of output: 2298


Script:

#!/bin/bash
# Look for validation or processing logic related to refills
ast-grep --pattern 'if ($_ === "never") {
  $$$
}'

Length of output: 52


Script:

#!/bin/bash
# Search for any refill-related logic
rg "refill" --type ts -A 5

Length of output: 90681

refillDay: z.number().int().min(1).max(31).optional(),
})
.optional(),
Expand Down
4 changes: 2 additions & 2 deletions apps/dashboard/lib/trpc/routers/key/updateRemaining.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export const updateKeyRemaining = t.procedure
remaining: z.number().int().positive().optional(),
refill: z
.object({
interval: z.enum(["daily", "monthly", "none"]),
amount: z.number().int().min(1).optional(),
interval: z.enum(["daily", "monthly", "never", "none"]),
amount: z.number().int().min(0).optional(),
refillDay: z.number().int().min(1).max(31).optional(),
})
.optional(),
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/lib/zod-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const formSchema = z.object({
.positive({ message: "Please enter a positive number" }),
refill: z
.object({
interval: z.enum(["none", "daily", "monthly"]),
interval: z.enum(["none", "daily", "monthly", "never"]),
amount: z.coerce
.number({
errorMap: (issue, { defaultError }) => ({
Expand Down
6 changes: 5 additions & 1 deletion internal/db/src/schema/key_migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ export const keyMigrationErrors = mysqlTable("key_migration_errors", {
permissions?: string[];
expires?: number;
remaining?: number;
refill?: { interval: "daily" | "monthly"; amount: number; refillDay?: number | undefined };
refill?: {
interval: "daily" | "monthly" | "never";
amount: number;
refillDay?: number | undefined;
};
ratelimit?: { async: boolean; limit: number; duration: number };
enabled: boolean;
environment?: string;
Expand Down
2 changes: 1 addition & 1 deletion internal/db/src/schema/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const keys = mysqlTable(
/**
* You can refill uses to keys at a desired interval
*/
refillInterval: mysqlEnum("refill_interval", ["daily", "monthly"]),
refillInterval: mysqlEnum("refill_interval", ["daily", "monthly", "never"]),
refillDay: tinyint("refill_day"),
refillAmount: int("refill_amount"),
lastRefillAt: datetime("last_refill_at", { fsp: 3 }),
Expand Down
Loading