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: removal of refillInterval #2709

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 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
1 change: 0 additions & 1 deletion apps/api/src/pkg/key_migration/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ export async function migrateKey(
createdAt: new Date(),
createdAtM: Date.now(),
expires: message.expires ? new Date(message.expires) : null,
refillInterval: message.refill?.interval,
refillAmount: message.refill?.amount,
refillDay: message.refill?.refillDay,
enabled: message.enabled,
Expand Down
3 changes: 1 addition & 2 deletions apps/api/src/pkg/key_migration/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export type MessageBody = {
keyAuthId: string;
rootKeyId: string;
prefix?: string;

name?: string;
hash: string;
start?: string;
Expand All @@ -14,7 +13,7 @@ export type MessageBody = {
permissions?: string[];
expires?: number;
remaining?: number;
refill?: { interval: "daily" | "monthly"; amount: number; refillDay?: number };
refill?: { amount: number; refillDay?: number };
ratelimit?: { async: boolean; limit: number; duration: number };
enabled: boolean;
environment?: string;
Expand Down
8 changes: 1 addition & 7 deletions apps/api/src/routes/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,18 +58,13 @@ export const keySchema = z
}),
refill: z
.object({
interval: z.enum(["daily", "monthly"]).openapi({
MichaelUnkey marked this conversation as resolved.
Show resolved Hide resolved
description:
"Determines the rate at which verifications will be refilled. When 'daily' is set for 'interval' 'refillDay' will be set to null.",
example: "daily",
}),
amount: z.number().int().openapi({
description: "Resets `remaining` to this value every interval.",
example: 100,
}),
refillDay: z.number().min(1).max(31).default(1).nullable().openapi({
description:
"The day verifications will refill each month, when interval is set to 'monthly'. Value is not zero-indexed making 1 the first day of the month. If left blank it will default to the first day of the month. When 'daily' is set for 'interval' 'refillDay' will be set to null.",
"The amount will refill on the day of the month specified on `refillDay`. If `refillDay` beyond the last day in the month, it will refill on the last day of the month. If left empty, it will refill daily.",
example: 15,
}),
lastRefillAt: z.number().int().optional().openapi({
Expand All @@ -82,7 +77,6 @@ export const keySchema = z
description:
"Unkey allows you to refill remaining verifications on a key on a regular interval.",
example: {
interval: "monthly",
amount: 10,
refillDay: 10,
},
Expand Down
5 changes: 2 additions & 3 deletions apps/api/src/routes/v1_apis_listKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,11 +337,10 @@ export const registerV1ApisListKeys = (app: App) =>
: undefined,
remaining: k.remaining ?? undefined,
refill:
k.refillInterval && k.refillAmount && k.lastRefillAt
k.refillAmount && k.lastRefillAt
? {
interval: k.refillInterval,
amount: k.refillAmount,
refillDay: k.refillInterval === "monthly" && k.refillDay ? k.refillDay : null,
refillDay: k.refillDay ?? null,
lastRefillAt: k.lastRefillAt?.getTime(),
}
: undefined,
Expand Down
32 changes: 0 additions & 32 deletions apps/api/src/routes/v1_keys_createKey.error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,35 +118,3 @@ test("when key recovery is not enabled", async (t) => {
},
});
});

test("reject invalid refill config when daily interval has non-null refillDay", async (t) => {
const h = await IntegrationHarness.init(t);

const root = await h.createRootKey([`api.${h.resources.userApi.id}.create_key`]);

const res = await h.post<V1KeysCreateKeyRequest, V1KeysCreateKeyResponse>({
url: "/v1/keys.createKey",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${root.key}`,
},
body: {
byteLength: 16,
apiId: h.resources.userApi.id,
remaining: 10,
refill: {
amount: 100,
refillDay: 4,
interval: "daily",
},
},
});
expect(res.status).toEqual(400);
expect(res.body).toMatchObject({
error: {
code: "BAD_REQUEST",
docs: "https://unkey.dev/docs/api-reference/errors/code/BAD_REQUEST",
message: "when interval is set to 'daily', 'refillDay' must be null.",
},
});
});
31 changes: 0 additions & 31 deletions apps/api/src/routes/v1_keys_createKey.happy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,35 +467,4 @@ describe("with externalId", () => {
expect(key!.identity!.id).toEqual(identity.id);
});
});
describe("Should default first day of month if none provided", () => {
test("should provide default value", async (t) => {
const h = await IntegrationHarness.init(t);
const root = await h.createRootKey([`api.${h.resources.userApi.id}.create_key`]);

const res = await h.post<V1KeysCreateKeyRequest, V1KeysCreateKeyResponse>({
url: "/v1/keys.createKey",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${root.key}`,
},
body: {
apiId: h.resources.userApi.id,
remaining: 10,
refill: {
interval: "monthly",
amount: 20,
refillDay: undefined,
},
},
});

expect(res.status, `expected 200, received: ${JSON.stringify(res, null, 2)}`).toBe(200);

const key = await h.db.primary.query.keys.findFirst({
where: (table, { eq }) => eq(table.id, res.body.keyId),
});
expect(key).toBeDefined();
expect(key!.refillDay).toEqual(1);
});
});
});
15 changes: 5 additions & 10 deletions apps/api/src/routes/v1_keys_createKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,6 @@ 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({
MichaelUnkey marked this conversation as resolved.
Show resolved Hide resolved
description: "Unkey will automatically refill verifications at the set interval.",
}),
amount: z.number().int().min(1).positive().openapi({
description:
"The number of verifications to refill for each occurrence is determined individually for each key.",
Expand All @@ -131,7 +128,6 @@ When validating a key, we will return this back to you, so you can clearly ident
description:
"Unkey enables you to refill verifications for each key at regular intervals.",
example: {
interval: "monthly",
amount: 100,
refillDay: 15,
},
Expand Down Expand Up @@ -312,16 +308,16 @@ export const registerV1KeysCreateKey = (app: App) =>
message: "remaining must be greater than 0.",
});
}
if ((req.remaining === null || req.remaining === undefined) && req.refill?.interval) {
if (req.remaining === null || req.remaining === undefined) {
throw new UnkeyApiError({
code: "BAD_REQUEST",
message: "remaining must be set if you are using refill.",
});
}
if (req.refill?.refillDay && req.refill.interval === "daily") {
if (req.refill && !req.refill.amount) {
throw new UnkeyApiError({
code: "BAD_REQUEST",
message: "when interval is set to 'daily', 'refillDay' must be null.",
message: "refill.amount must be set if you are using refill.",
});
}
/**
Expand Down Expand Up @@ -372,10 +368,9 @@ export const registerV1KeysCreateKey = (app: App) =>
ratelimitLimit: req.ratelimit?.limit ?? req.ratelimit?.refillRate,
ratelimitDuration: req.ratelimit?.duration ?? req.ratelimit?.refillInterval,
remaining: req.remaining,
refillInterval: req.refill?.interval,
refillDay: req.refill?.interval === "daily" ? null : req?.refill?.refillDay ?? 1,
refillDay: req?.refill?.refillDay ?? null,
refillAmount: req.refill?.amount,
lastRefillAt: req.refill?.interval ? new Date() : null,
lastRefillAt: null,
deletedAt: null,
enabled: req.enabled,
environment: req.environment ?? null,
Expand Down
16 changes: 7 additions & 9 deletions apps/api/src/routes/v1_keys_getKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,13 @@ export const registerV1KeysGetKey = (app: App) =>
updatedAt: key.updatedAtM ?? undefined,
expires: key.expires?.getTime() ?? undefined,
remaining: key.remaining ?? undefined,
refill:
key.refillInterval && key.refillAmount
? {
interval: key.refillInterval,
amount: key.refillAmount,
refillDay: key.refillInterval === "monthly" ? key.refillDay : null,
lastRefillAt: key.lastRefillAt?.getTime(),
}
: undefined,
refill: key.refillAmount
? {
amount: key.refillAmount,
refillDay: key.refillDay ?? null,
lastRefillAt: key.lastRefillAt?.getTime(),
}
: undefined,
ratelimit:
key.ratelimitAsync !== null && key.ratelimitLimit !== null && key.ratelimitDuration !== null
? {
Expand Down
1 change: 0 additions & 1 deletion apps/api/src/routes/v1_keys_updateKey.happy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,6 @@ describe("When refillDay is omitted.", () => {
expect(found).toBeDefined();
expect(found?.remaining).toEqual(10);
expect(found?.refillAmount).toEqual(130);
expect(found?.refillInterval).toEqual("monthly");
expect(found?.refillDay).toEqual(1);
});
});
Expand Down
2 changes: 0 additions & 2 deletions apps/api/src/routes/v1_keys_updateKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,10 @@ export const registerV1KeysUpdate = (app: App) =>

if (typeof req.refill !== "undefined") {
if (req.refill === null) {
changes.refillInterval = null;
changes.refillAmount = null;
changes.refillDay = null;
changes.lastRefillAt = null;
} else {
changes.refillInterval = req.refill.interval;
changes.refillAmount = req.refill.amount;
changes.refillDay = req.refill.refillDay ?? 1;
}
Expand Down
36 changes: 0 additions & 36 deletions apps/api/src/routes/v1_migrations_createKey.error.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,39 +112,3 @@ test("reject invalid ratelimit config", async (t) => {
expect(res.status).toEqual(400);
expect(res.body.error.code).toEqual("BAD_REQUEST");
});
test("reject invalid refill config when daily interval has non-null refillDay", async (t) => {
const h = await IntegrationHarness.init(t);
const { key } = await h.createRootKey(["*"]);

const res = await h.post<V1MigrationsCreateKeysRequest, ErrorResponse>({
url: "/v1/migrations.createKeys",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${key}`,
},
body: [
{
start: "x",
hash: {
value: "x",
variant: "sha256_base64",
},
apiId: h.resources.userApi.id,
remaining: 10,
refill: {
amount: 100,
refillDay: 4,
interval: "daily",
},
},
],
});
expect(res.status).toEqual(400);
expect(res.body).toMatchObject({
error: {
code: "BAD_REQUEST",
docs: "https://unkey.dev/docs/api-reference/errors/code/BAD_REQUEST",
message: "when interval is set to 'daily', 'refillDay' must be null.",
},
});
});
2 changes: 0 additions & 2 deletions apps/api/src/routes/v1_migrations_createKey.happy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,6 @@ describe("Should default to first day of month if none provided", () => {
enabled: true,
remaining: 10,
refill: {
interval: "monthly",
amount: 100,
refillDay: undefined,
},
Expand All @@ -536,7 +535,6 @@ describe("Should default to first day of month if none provided", () => {
expect(found).toBeDefined();
expect(found?.remaining).toEqual(10);
expect(found?.refillAmount).toEqual(100);
expect(found?.refillInterval).toEqual("monthly");
expect(found?.refillDay).toEqual(1);
expect(found?.hash).toEqual(hash);
});
Expand Down
31 changes: 13 additions & 18 deletions apps/api/src/routes/v1_migrations_createKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,25 +123,26 @@ 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({
description:
"Unkey will automatically refill verifications at the set interval.",
}),
amount: z.number().int().min(1).positive().openapi({
description:
"The number of verifications to refill for each occurrence is determined individually for each key.",
}),
refillDay: z.number().min(1).max(31).optional().openapi({
description:
"The day verifications will refill each month, when interval is set to 'monthly'",
}),
refillDay: z
.number()
.min(1)
.max(31)
.optional()
.openapi({
description: `The day of the month, when we will refill the remaining verifications. To refill on the 15th of each month, set 'refillDay': 15.
If the day does not exist, for example you specified the 30th and it's february, we will refill them on the last day of the month instead.`,
}),
})
.optional()
.openapi({
description:
"Unkey enables you to refill verifications for each key at regular intervals.",
example: {
interval: "daily",
refillDay: 15,
amount: 100,
},
}),
Expand Down Expand Up @@ -378,7 +379,7 @@ export const registerV1MigrationsCreateKeys = (app: App) =>
});
}

if ((key.remaining === null || key.remaining === undefined) && key.refill?.interval) {
if (key.remaining === null || key.remaining === undefined) {
throw new UnkeyApiError({
code: "BAD_REQUEST",
message: "remaining must be set if you are using refill.",
Expand All @@ -391,12 +392,7 @@ export const registerV1MigrationsCreateKeys = (app: App) =>
message: "provide either `hash` or `plaintext`",
});
}
if (key.refill?.refillDay && key.refill.interval === "daily") {
throw new UnkeyApiError({
code: "BAD_REQUEST",
message: "when interval is set to 'daily', 'refillDay' must be null.",
});
}

/**
* Set up an api for production
*/
Expand All @@ -420,8 +416,7 @@ export const registerV1MigrationsCreateKeys = (app: App) =>
ratelimitLimit: key.ratelimit?.limit ?? key.ratelimit?.refillRate ?? null,
ratelimitDuration: key.ratelimit?.refillInterval ?? key.ratelimit?.refillInterval ?? null,
remaining: key.remaining ?? null,
refillInterval: key.refill?.interval ?? null,
refillDay: key.refill?.interval === "daily" ? null : key?.refill?.refillDay ?? 1,
refillDay: key?.refill?.refillDay ?? 1,
refillAmount: key.refill?.amount ?? null,
deletedAt: null,
enabled: key.enabled ?? true,
Expand Down
Loading
Loading