diff --git a/apps/api/src/pkg/key_migration/message.ts b/apps/api/src/pkg/key_migration/message.ts index 91a9e39ccc..049f69bb94 100644 --- a/apps/api/src/pkg/key_migration/message.ts +++ b/apps/api/src/pkg/key_migration/message.ts @@ -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; diff --git a/apps/api/src/routes/schema.ts b/apps/api/src/routes/schema.ts index a9d4d4b14b..d2ac3e3020 100644 --- a/apps/api/src/routes/schema.ts +++ b/apps/api/src/routes/schema.ts @@ -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", diff --git a/apps/api/src/routes/v1_keys_createKey.ts b/apps/api/src/routes/v1_keys_createKey.ts index cb0ed1c5f0..2c86c739c5 100644 --- a/apps/api/src/routes/v1_keys_createKey.ts +++ b/apps/api/src/routes/v1_keys_createKey.ts @@ -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.", }), diff --git a/apps/api/src/routes/v1_keys_updateKey.ts b/apps/api/src/routes/v1_keys_updateKey.ts index d12c521896..969faa3341 100644 --- a/apps/api/src/routes/v1_keys_updateKey.ts +++ b/apps/api/src/routes/v1_keys_updateKey.ts @@ -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.", }), diff --git a/apps/api/src/routes/v1_migrations_createKey.ts b/apps/api/src/routes/v1_migrations_createKey.ts index a9fd772504..3487bc6b12 100644 --- a/apps/api/src/routes/v1_migrations_createKey.ts +++ b/apps/api/src/routes/v1_migrations_createKey.ts @@ -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.", }), diff --git a/apps/api/src/routes/v1_migrations_enqueueKeys.ts b/apps/api/src/routes/v1_migrations_enqueueKeys.ts index a21d6931ea..f6ae347cb4 100644 --- a/apps/api/src/routes/v1_migrations_enqueueKeys.ts +++ b/apps/api/src/routes/v1_migrations_enqueueKeys.ts @@ -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.", }), diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/settings/update-key-remaining.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/settings/update-key-remaining.tsx index 57b235ce45..2a96da2a22 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/settings/update-key-remaining.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/settings/update-key-remaining.tsx @@ -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({ @@ -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; }; @@ -196,6 +195,7 @@ export const UpdateKeyRemaining: React.FC = ({ apiKey }) => { None Daily Monthly + Never diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/new/client.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/new/client.tsx index ebcecf9150..0ac478e55e 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/new/client.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/new/client.tsx @@ -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; @@ -510,6 +512,7 @@ export const CreateKey = ({ apiId, keyAuthId, defaultBytes, defaultPrefix }: Pro Daily Monthly + Never @@ -520,6 +523,7 @@ export const CreateKey = ({ apiId, keyAuthId, defaultBytes, defaultPrefix }: Pro /> ( @@ -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 } /> @@ -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 }) => ( diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/new/validation.ts b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/new/validation.ts index 69d47f70ca..d6416a9724 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/new/validation.ts +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/new/validation.ts @@ -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 }) => ({ @@ -62,8 +62,8 @@ export const formSchema = z.object({ }), }) .int() - .min(1) - .positive(), + .min(0) + .optional(), refillDay: z.coerce .number({ errorMap: (issue, { defaultError }) => ({ diff --git a/apps/dashboard/lib/trpc/routers/key/create.ts b/apps/dashboard/lib/trpc/routers/key/create.ts index 93fb4c659f..6dde5e1991 100644 --- a/apps/dashboard/lib/trpc/routers/key/create.ts +++ b/apps/dashboard/lib/trpc/routers/key/create.ts @@ -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), refillDay: z.number().int().min(1).max(31).optional(), }) .optional(), diff --git a/apps/dashboard/lib/trpc/routers/key/updateRemaining.ts b/apps/dashboard/lib/trpc/routers/key/updateRemaining.ts index 835ece954c..d39e4d59ce 100644 --- a/apps/dashboard/lib/trpc/routers/key/updateRemaining.ts +++ b/apps/dashboard/lib/trpc/routers/key/updateRemaining.ts @@ -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(), diff --git a/apps/dashboard/lib/zod-helper.ts b/apps/dashboard/lib/zod-helper.ts index 7970b612ec..a7fd561809 100644 --- a/apps/dashboard/lib/zod-helper.ts +++ b/apps/dashboard/lib/zod-helper.ts @@ -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 }) => ({ diff --git a/internal/db/src/schema/key_migrations.ts b/internal/db/src/schema/key_migrations.ts index 0c3470435b..4b80fb8e02 100644 --- a/internal/db/src/schema/key_migrations.ts +++ b/internal/db/src/schema/key_migrations.ts @@ -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; diff --git a/internal/db/src/schema/keys.ts b/internal/db/src/schema/keys.ts index 81360f3d9a..93d5a50e3a 100644 --- a/internal/db/src/schema/keys.ts +++ b/internal/db/src/schema/keys.ts @@ -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 }),