From 0a496f03b8ea2c92abfbc92086f9e1e57b4f9409 Mon Sep 17 00:00:00 2001 From: RajuGangitla Date: Sun, 6 Oct 2024 18:43:19 +0000 Subject: [PATCH 1/4] fix:changed the permission view --- .../[apiId]/keys/[keyAuthId]/[keyId]/page.tsx | 47 +- .../[keyAuthId]/[keyId]/permission-list.tsx | 111 ++ .../authorization/roles/[roleId]/tree.tsx | 2 +- apps/dashboard/app/layout.tsx | 2 + apps/engineering/app/layout.tsx | 2 + apps/planetfall/app/layout.tsx | 6 +- apps/workflows/app/layout.tsx | 6 +- packages/api/src/openapi.d.ts | 1105 ++++++++--------- 8 files changed, 710 insertions(+), 571 deletions(-) create mode 100644 apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx index f079901c73..a9ae46cbaf 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx @@ -11,7 +11,7 @@ import { Button, buttonVariants } from "@/components/ui/button"; import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { getTenantId } from "@/lib/auth"; -import { and, db, eq, isNull, schema } from "@/lib/db"; +import { and, db, eq, isNull, Role, schema } from "@/lib/db"; import { formatNumber } from "@/lib/fmt"; import { getLastUsed, @@ -25,6 +25,9 @@ import ms from "ms"; import { notFound } from "next/navigation"; import { Chart } from "./chart"; import { VerificationTable } from "./verification-table"; +import RolePermissionsTree from "./permission-list"; +import { NestedPermissions } from "@/app/(app)/authorization/roles/[roleId]/tree"; +import PermissionTree from "./permission-list"; export default async function APIKeyDetailPage(props: { params: { @@ -71,6 +74,8 @@ export default async function APIKeyDetailPage(props: { }, }, }); + + if (!key || key.workspace.tenantId !== tenantId) { return notFound(); } @@ -155,6 +160,41 @@ export default async function APIKeyDetailPage(props: { } } + const roleTee = key.workspace.roles.map((role) => { + + const nested: NestedPermissions = {}; + for (const permission of key.workspace.permissions) { + let n = nested; + const parts = permission.name.split("."); + for (let i = 0; i < parts.length; i++) { + const p = parts[i]; + if (!(p in n)) { + n[p] = { + id: permission.id, + name: permission.name, + description: permission.description, + checked: role.permissions.some((p) => p.permissionId === permission.id), + part: p, + permissions: {}, + path: parts.slice(0, i).join("."), + }; + } + n = n[p].permissions; + } + } + let data = { + id: role.id, + name: role.name, + description: role.description, + keyId: key.id, + active: key.roles.some((keyRole) => keyRole.roleId === role.id), + nestedPermissions: nested + } + return data + }) + + + return (
@@ -308,7 +348,8 @@ export default async function APIKeyDetailPage(props: {
- + {/* + /> */} ); diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx new file mode 100644 index 0000000000..329d8b50ea --- /dev/null +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx @@ -0,0 +1,111 @@ +"use client" +import React, { useState, useEffect } from 'react'; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; +import { Label } from "@/components/ui/label"; +import { Switch } from "@/components/ui/switch"; +import { RecursivePermission } from '@/app/(app)/authorization/roles/[roleId]/tree'; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; +import { CopyButton } from '@/components/dashboard/copy-button'; +import { RoleToggle } from './role-toggle'; +import { ChevronRight } from 'lucide-react'; + +export type NestedPermission = { + id: string; + checked: boolean; + description: string | null; + name: string; + part: string; + path: string; + permissions: NestedPermissions; +}; + +export type NestedPermissions = Record; + +export type Role = { + id: string; + name: string; + keyId: string + active: boolean + description: string | null; + nestedPermissions: NestedPermissions; +}; + +type PermissionTreeProps = { + roles: Role[]; +}; + + +export default function PermissionTree({ roles }: PermissionTreeProps) { + const [openAll, setOpenAll] = useState(false); + const [openRoles, setOpenRoles] = useState([]); + + useEffect(() => { + setOpenRoles(openAll ? roles.map(role => role.id) : []); + }, [openAll, roles]); + + return ( + + +
+ Permissions +
+
+ + +
+
+ + + {roles.map(role => { + const isOpen = openRoles.includes(role.id); + return ( + { + setOpenRoles(prev => + open + ? [...prev, role.id] + : prev.filter(id => id !== role.id) + ); + }} + > + + + + + +
{role.name}
+
+ +
+
{role.name}
+
+ +
+
+
+
+ +
+ +
+ {Object.entries(role.nestedPermissions).map(([k, p]) => ( + + ))} +
+
+
+ ); + })} +
+
+ ); +} \ No newline at end of file diff --git a/apps/dashboard/app/(app)/authorization/roles/[roleId]/tree.tsx b/apps/dashboard/app/(app)/authorization/roles/[roleId]/tree.tsx index e8af830dc4..8e5746694d 100644 --- a/apps/dashboard/app/(app)/authorization/roles/[roleId]/tree.tsx +++ b/apps/dashboard/app/(app)/authorization/roles/[roleId]/tree.tsx @@ -56,7 +56,7 @@ export const Tree: React.FC = ({ nestedPermissions, role }) => { ); }; -const RecursivePermission: React.FC< +export const RecursivePermission: React.FC< NestedPermission & { k: string; roleId: string; openAll: boolean } > = ({ k, openAll, id, name, permissions, roleId, checked, description }) => { const [open, setOpen] = useState(openAll); diff --git a/apps/dashboard/app/layout.tsx b/apps/dashboard/app/layout.tsx index 09c23c7d3c..17dba12566 100644 --- a/apps/dashboard/app/layout.tsx +++ b/apps/dashboard/app/layout.tsx @@ -15,6 +15,8 @@ import { ThemeProvider } from "./theme-provider"; const inter = Inter({ subsets: ["latin"], variable: "--font-inter", + display: 'swap', + adjustFontFallback: false }); const pangea = localFont({ diff --git a/apps/engineering/app/layout.tsx b/apps/engineering/app/layout.tsx index 182e4dae01..a9d8d41c4e 100644 --- a/apps/engineering/app/layout.tsx +++ b/apps/engineering/app/layout.tsx @@ -6,6 +6,8 @@ import "./global.css"; const inter = Inter({ subsets: ["latin"], + display: 'swap', + adjustFontFallback: false }); export default function Layout({ children }: { children: ReactNode }) { diff --git a/apps/planetfall/app/layout.tsx b/apps/planetfall/app/layout.tsx index 3314e4780a..4fa62083e4 100644 --- a/apps/planetfall/app/layout.tsx +++ b/apps/planetfall/app/layout.tsx @@ -2,7 +2,11 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; import "./globals.css"; -const inter = Inter({ subsets: ["latin"] }); +const inter = Inter({ + subsets: ["latin"], + display: 'swap', + adjustFontFallback: false +}); export const metadata: Metadata = { title: "Create Next App", diff --git a/apps/workflows/app/layout.tsx b/apps/workflows/app/layout.tsx index bf4fc28121..26fb26f5b7 100644 --- a/apps/workflows/app/layout.tsx +++ b/apps/workflows/app/layout.tsx @@ -1,7 +1,11 @@ import type { Metadata } from "next"; import { Inter } from "next/font/google"; -const inter = Inter({ subsets: ["latin"] }); +const inter = Inter({ + subsets: ["latin"], + display: 'swap', + adjustFontFallback: false +}); export const metadata: Metadata = { title: "Create Next App", diff --git a/packages/api/src/openapi.d.ts b/packages/api/src/openapi.d.ts index ac451fca07..2c495e9eb1 100644 --- a/packages/api/src/openapi.d.ts +++ b/packages/api/src/openapi.d.ts @@ -3,14 +3,11 @@ * Do not make direct changes to the file. */ + /** OneOf type helpers */ type Without = { [P in Exclude]?: never }; -type XOR = T | U extends object ? (Without & U) | (Without & T) : T | U; -type OneOf = T extends [infer Only] - ? Only - : T extends [infer A, infer B, ...infer Rest] - ? OneOf<[XOR, ...Rest]> - : never; +type XOR = (T | U) extends object ? (Without & U) | (Without & T) : T | U; +type OneOf = T extends [infer Only] ? Only : T extends [infer A, infer B, ...infer Rest] ? OneOf<[XOR, ...Rest]> : never; export interface paths { "/v1/liveness": { @@ -521,16 +518,7 @@ export interface components { * * @enum {string} */ - code: - | "VALID" - | "NOT_FOUND" - | "FORBIDDEN" - | "USAGE_EXCEEDED" - | "RATE_LIMITED" - | "UNAUTHORIZED" - | "DISABLED" - | "INSUFFICIENT_PERMISSIONS" - | "EXPIRED"; + code: "VALID" | "NOT_FOUND" | "FORBIDDEN" | "USAGE_EXCEEDED" | "RATE_LIMITED" | "UNAUTHORIZED" | "DISABLED" | "INSUFFICIENT_PERMISSIONS" | "EXPIRED"; /** @description Sets the key to be enabled or disabled. Disabled keys will not verify. */ enabled?: boolean; /** @@ -556,18 +544,11 @@ export interface components { }; }; /** @description A query for which permissions you require */ - PermissionQuery: OneOf< - [ - string, - { - and: components["schemas"]["PermissionQuery"][]; - }, - { - or: components["schemas"]["PermissionQuery"][]; - }, - null, - ] - >; + PermissionQuery: OneOf<[string, { + and: components["schemas"]["PermissionQuery"][]; + }, { + or: components["schemas"]["PermissionQuery"][]; + }, null]>; V1KeysVerifyKeyRequest: { /** * @description The id of the api where the key belongs to. This is optional for now but will be required soon. @@ -612,21 +593,21 @@ export interface components { * ] */ ratelimits?: { - /** - * @description The name of the ratelimit. - * @example tokens - */ - name: string; - /** - * @description Optionally override how expensive this operation is and how many tokens are deducted from the current limit. - * @default 1 - */ - cost?: number; - /** @description Optionally override the limit. */ - limit?: number; - /** @description Optionally override the ratelimit window duration. */ - duration?: number; - }[]; + /** + * @description The name of the ratelimit. + * @example tokens + */ + name: string; + /** + * @description Optionally override how expensive this operation is and how many tokens are deducted from the current limit. + * @default 1 + */ + cost?: number; + /** @description Optionally override the limit. */ + limit?: number; + /** @description Optionally override the ratelimit window duration. */ + duration?: number; + }[]; }; ErrDeleteProtected: { error: { @@ -652,7 +633,8 @@ export interface components { }; }; responses: never; - parameters: {}; + parameters: { + }; requestBodies: never; headers: never; pathItems: never; @@ -663,6 +645,7 @@ export type $defs = Record; export type external = Record; export interface operations { + "v1.liveness": { responses: { /** @description The configured services and their status */ @@ -1190,7 +1173,7 @@ export interface operations { * "refillInterval": 60 * } */ - ratelimit?: { + ratelimit?: ({ /** * @deprecated * @description Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. @@ -1222,7 +1205,7 @@ export interface operations { * This field will become required in a future version. */ duration?: number; - } | null; + }) | null; /** * @description The number of requests that can be made with this key before it becomes invalid. Set `null` to disable. * @example 1000 @@ -1235,7 +1218,7 @@ export interface operations { * "amount": 100 * } */ - refill?: { + refill?: ({ /** * @description Unkey will automatically refill verifications at the set interval. If null is used the refill functionality will be removed from the key. * @enum {string} @@ -1243,7 +1226,7 @@ export interface operations { interval: "daily" | "monthly"; /** @description The amount of verifications to refill for each occurrence is determined individually for each key. */ amount: number; - } | null; + }) | null; /** * @description Set if key is enabled or disabled. If disabled, the key cannot be used to verify. * @example true @@ -1266,16 +1249,16 @@ export interface operations { * ] */ roles?: { - /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; /** * @description The permissions you want to set for this key. This overwrites all existing permissions. * Setting permissions requires the `rbac.*.add_permission_to_key` permission. @@ -1293,16 +1276,16 @@ export interface operations { * ] */ permissions?: { - /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1452,27 +1435,27 @@ export interface operations { content: { "application/json": { verifications: { - /** - * @description The timestamp of the usage data - * @example 1620000000000 - */ - time: number; - /** - * @description The number of successful requests - * @example 100 - */ - success: number; - /** - * @description The number of requests that were rate limited - * @example 10 - */ - rateLimited: number; - /** - * @description The number of requests that exceeded the usage limit - * @example 0 - */ - usageExceeded: number; - }[]; + /** + * @description The timestamp of the usage data + * @example 1620000000000 + */ + time: number; + /** + * @description The number of successful requests + * @example 100 + */ + success: number; + /** + * @description The number of requests that were rate limited + * @example 10 + */ + rateLimited: number; + /** + * @description The number of requests that exceeded the usage limit + * @example 0 + */ + usageExceeded: number; + }[]; }; }; }; @@ -1528,16 +1511,16 @@ export interface operations { keyId: string; /** @description The permissions you want to add to this key */ permissions: { - /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1546,17 +1529,17 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the permission. This is used internally - * @example perm_123 - */ - id: string; - /** - * @description The name of the permission - * @example dns.record.create - */ - name: string; - }[]; + /** + * @description The id of the permission. This is used internally + * @example perm_123 + */ + id: string; + /** + * @description The name of the permission + * @example dns.record.create + */ + name: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -1621,11 +1604,11 @@ export interface operations { * ] */ permissions: { - /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - }[]; + /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + }[]; }; }; }; @@ -1703,16 +1686,16 @@ export interface operations { * ] */ permissions: { - /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1721,17 +1704,17 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the permission. This is used internally - * @example perm_123 - */ - id: string; - /** - * @description The name of the permission - * @example dns.record.create - */ - name: string; - }[]; + /** + * @description The id of the permission. This is used internally + * @example perm_123 + */ + id: string; + /** + * @description The name of the permission + * @example dns.record.create + */ + name: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -1801,16 +1784,16 @@ export interface operations { * ] */ roles: { - /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1819,17 +1802,17 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the role. This is used internally - * @example role_123 - */ - id: string; - /** - * @description The name of the role - * @example dns.record.create - */ - name: string; - }[]; + /** + * @description The id of the role. This is used internally + * @example role_123 + */ + id: string; + /** + * @description The name of the role + * @example dns.record.create + */ + name: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -1894,11 +1877,11 @@ export interface operations { * ] */ roles: { - /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - }[]; + /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + }[]; }; }; }; @@ -1976,16 +1959,16 @@ export interface operations { * ] */ roles: { - /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1994,17 +1977,17 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the role. This is used internally - * @example role_123 - */ - id: string; - /** - * @description The name of the role - * @example dns.record.create - */ - name: string; - }[]; + /** + * @description The id of the role. This is used internally + * @example role_123 + */ + id: string; + /** + * @description The name of the role + * @example dns.record.create + */ + name: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -2453,26 +2436,26 @@ export interface operations { * ] */ resources?: { - /** - * @description The type of resource - * @example organization - */ - type: string; - /** - * @description The unique identifier for the resource - * @example org_123 - */ - id: string; - /** - * @description A human readable name for this resource - * @example unkey - */ - name?: string; - /** @description Attach any metadata to this resources */ - meta?: { - [key: string]: unknown; - }; - }[]; + /** + * @description The type of resource + * @example organization + */ + type: string; + /** + * @description The unique identifier for the resource + * @example org_123 + */ + id: string; + /** + * @description A human readable name for this resource + * @example unkey + */ + name?: string; + /** @description Attach any metadata to this resources */ + meta?: { + [key: string]: unknown; + }; + }[]; }; }; }; @@ -2550,230 +2533,18 @@ export interface operations { "v1.migrations.createKeys": { requestBody: { content: { - "application/json": { - /** - * @description Choose an `API` where this key should be created. - * @example api_123 - */ - apiId: string; - /** - * @description To make it easier for your users to understand which product an api key belongs to, you can add prefix them. - * - * For example Stripe famously prefixes their customer ids with cus_ or their api keys with sk_live_. - * - * The underscore is automatically added if you are defining a prefix, for example: "prefix": "abc" will result in a key like abc_xxxxxxxxx - */ - prefix?: string; - /** - * @description The name for your Key. This is not customer facing. - * @example my key - */ - name?: string; - /** @description The raw key in plaintext. If provided, unkey encrypts this value and stores it securely. Provide either `hash` or `plaintext` */ - plaintext?: string; - /** @description Provide either `hash` or `plaintext` */ - hash?: { - /** @description The hashed and encoded key */ - value: string; + "application/json": ({ /** - * @description The algorithm for hashing and encoding, currently only sha256 and base64 are supported - * @enum {string} + * @description Choose an `API` where this key should be created. + * @example api_123 */ - variant: "sha256_base64"; - }; - /** - * @description The first 4 characters of the key. If a prefix is used, it should be the prefix plus 4 characters. - * @example unkey_32kq - */ - start?: string; - /** - * @description Your user’s Id. This will provide a link between Unkey and your customer record. - * When validating a key, we will return this back to you, so you can clearly identify your user from their api key. - * @example team_123 - */ - ownerId?: string; - /** - * @description This is a place for dynamic meta data, anything that feels useful for you should go here - * @example { - * "billingTier": "PRO", - * "trialEnds": "2023-06-16T17:16:37.161Z" - * } - */ - meta?: { - [key: string]: unknown; - }; - /** - * @description A list of roles that this key should have. If the role does not exist, an error is thrown - * @example [ - * "admin", - * "finance" - * ] - */ - roles?: string[]; - /** - * @description A list of permissions that this key should have. If the permission does not exist, an error is thrown - * @example [ - * "domains.create_record", - * "say_hello" - * ] - */ - permissions?: string[]; - /** - * @description You can auto expire keys by providing a unix timestamp in milliseconds. Once Keys expire they will automatically be disabled and are no longer valid unless you enable them again. - * @example 1623869797161 - */ - expires?: number; - /** - * @description You can limit the number of requests a key can make. Once a key reaches 0 remaining requests, it will automatically be disabled and is no longer valid unless you update it. - * @example 1000 - */ - remaining?: number; - /** - * @description Unkey enables you to refill verifications for each key at regular intervals. - * @example { - * "interval": "daily", - * "amount": 100 - * } - */ - refill?: { + apiId: string; /** - * @description Unkey will automatically refill verifications at the set interval. - * @enum {string} - */ - interval: "daily" | "monthly"; - /** @description The number of verifications to refill for each occurrence is determined individually for each key. */ - amount: number; - }; - /** - * @description Unkey comes with per-key ratelimiting out of the box. - * @example { - * "type": "fast", - * "limit": 10, - * "refillRate": 1, - * "refillInterval": 60 - * } - */ - ratelimit?: { - /** - * @description Async will return a response immediately, lowering latency at the cost of accuracy. - * @default false - */ - async?: boolean; - /** - * @deprecated - * @description Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. - * @default fast - * @enum {string} - */ - type?: "fast" | "consistent"; - /** @description The total amount of burstable requests. */ - limit: number; - /** - * @deprecated - * @description How many tokens to refill during each refillInterval. - */ - refillRate: number; - /** - * @deprecated - * @description Determines the speed at which tokens are refilled, in milliseconds. - */ - refillInterval: number; - }; - /** - * @description Sets if key is enabled or disabled. Disabled keys are not valid. - * @default true - * @example false - */ - enabled?: boolean; - /** - * @description Environments allow you to divide your keyspace. - * - * Some applications like Stripe, Clerk, WorkOS and others have a concept of "live" and "test" keys to - * give the developer a way to develop their own application without the risk of modifying real world - * resources. - * - * When you set an environment, we will return it back to you when validating the key, so you can - * handle it correctly. - */ - environment?: string; - }[]; - }; - }; - responses: { - /** @description The key ids of all created keys */ - 200: { - content: { - "application/json": { - /** - * @description The ids of the keys. This is not a secret and can be stored as a reference if you wish. You need the keyId to update or delete a key later. - * @example [ - * "key_123", - * "key_456" - * ] - */ - keyIds: string[]; - }; - }; - }; - /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ - 400: { - content: { - "application/json": components["schemas"]["ErrBadRequest"]; - }; - }; - /** @description Although the HTTP standard specifies "unauthorized", semantically this response means "unauthenticated". That is, the client must authenticate itself to get the requested response. */ - 401: { - content: { - "application/json": components["schemas"]["ErrUnauthorized"]; - }; - }; - /** @description The client does not have access rights to the content; that is, it is unauthorized, so the server is refusing to give the requested resource. Unlike 401 Unauthorized, the client's identity is known to the server. */ - 403: { - content: { - "application/json": components["schemas"]["ErrForbidden"]; - }; - }; - /** @description The server cannot find the requested resource. In the browser, this means the URL is not recognized. In an API, this can also mean that the endpoint is valid but the resource itself does not exist. Servers may also send this response instead of 403 Forbidden to hide the existence of a resource from an unauthorized client. This response code is probably the most well known due to its frequent occurrence on the web. */ - 404: { - content: { - "application/json": components["schemas"]["ErrNotFound"]; - }; - }; - /** @description This response is sent when a request conflicts with the current state of the server. */ - 409: { - content: { - "application/json": components["schemas"]["ErrConflict"]; - }; - }; - /** @description The user has sent too many requests in a given amount of time ("rate limiting") */ - 429: { - content: { - "application/json": components["schemas"]["ErrTooManyRequests"]; - }; - }; - /** @description The server has encountered a situation it does not know how to handle. */ - 500: { - content: { - "application/json": components["schemas"]["ErrInternalServerError"]; - }; - }; - }; - }; - "v1.migrations.enqueueKeys": { - requestBody: { - content: { - "application/json": { - /** @description Contact support@unkey.dev to receive your migration id. */ - migrationId: string; - /** @description The id of the api, you want to migrate keys to */ - apiId: string; - keys: { - /** - * @description To make it easier for your users to understand which product an api key belongs to, you can add prefix them. - * - * For example Stripe famously prefixes their customer ids with cus_ or their api keys with sk_live_. - * - * The underscore is automatically added if you are defining a prefix, for example: "prefix": "abc" will result in a key like abc_xxxxxxxxx + * @description To make it easier for your users to understand which product an api key belongs to, you can add prefix them. + * + * For example Stripe famously prefixes their customer ids with cus_ or their api keys with sk_live_. + * + * The underscore is automatically added if you are defining a prefix, for example: "prefix": "abc" will result in a key like abc_xxxxxxxxx */ prefix?: string; /** @@ -2857,43 +2628,39 @@ export interface operations { amount: number; }; /** - * @description Unkey comes with per-key fixed-window ratelimiting out of the box. + * @description Unkey comes with per-key ratelimiting out of the box. * @example { * "type": "fast", * "limit": 10, - * "duration": 60000 + * "refillRate": 1, + * "refillInterval": 60 * } */ ratelimit?: { /** * @description Async will return a response immediately, lowering latency at the cost of accuracy. - * @default true + * @default false */ async?: boolean; /** * @deprecated - * @description Deprecated, use `async`. Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. + * @description Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. * @default fast * @enum {string} */ type?: "fast" | "consistent"; - /** @description The total amount of requests in a given interval. */ + /** @description The total amount of burstable requests. */ limit: number; - /** - * @description The window duration in milliseconds - * @example 60000 - */ - duration: number; /** * @deprecated * @description How many tokens to refill during each refillInterval. */ - refillRate?: number; + refillRate: number; /** * @deprecated - * @description The refill timeframe, in milliseconds. + * @description Determines the speed at which tokens are refilled, in milliseconds. */ - refillInterval?: number; + refillInterval: number; }; /** * @description Sets if key is enabled or disabled. Disabled keys are not valid. @@ -2912,7 +2679,223 @@ export interface operations { * handle it correctly. */ environment?: string; - }[]; + })[]; + }; + }; + responses: { + /** @description The key ids of all created keys */ + 200: { + content: { + "application/json": { + /** + * @description The ids of the keys. This is not a secret and can be stored as a reference if you wish. You need the keyId to update or delete a key later. + * @example [ + * "key_123", + * "key_456" + * ] + */ + keyIds: string[]; + }; + }; + }; + /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ + 400: { + content: { + "application/json": components["schemas"]["ErrBadRequest"]; + }; + }; + /** @description Although the HTTP standard specifies "unauthorized", semantically this response means "unauthenticated". That is, the client must authenticate itself to get the requested response. */ + 401: { + content: { + "application/json": components["schemas"]["ErrUnauthorized"]; + }; + }; + /** @description The client does not have access rights to the content; that is, it is unauthorized, so the server is refusing to give the requested resource. Unlike 401 Unauthorized, the client's identity is known to the server. */ + 403: { + content: { + "application/json": components["schemas"]["ErrForbidden"]; + }; + }; + /** @description The server cannot find the requested resource. In the browser, this means the URL is not recognized. In an API, this can also mean that the endpoint is valid but the resource itself does not exist. Servers may also send this response instead of 403 Forbidden to hide the existence of a resource from an unauthorized client. This response code is probably the most well known due to its frequent occurrence on the web. */ + 404: { + content: { + "application/json": components["schemas"]["ErrNotFound"]; + }; + }; + /** @description This response is sent when a request conflicts with the current state of the server. */ + 409: { + content: { + "application/json": components["schemas"]["ErrConflict"]; + }; + }; + /** @description The user has sent too many requests in a given amount of time ("rate limiting") */ + 429: { + content: { + "application/json": components["schemas"]["ErrTooManyRequests"]; + }; + }; + /** @description The server has encountered a situation it does not know how to handle. */ + 500: { + content: { + "application/json": components["schemas"]["ErrInternalServerError"]; + }; + }; + }; + }; + "v1.migrations.enqueueKeys": { + requestBody: { + content: { + "application/json": { + /** @description Contact support@unkey.dev to receive your migration id. */ + migrationId: string; + /** @description The id of the api, you want to migrate keys to */ + apiId: string; + keys: ({ + /** + * @description To make it easier for your users to understand which product an api key belongs to, you can add prefix them. + * + * For example Stripe famously prefixes their customer ids with cus_ or their api keys with sk_live_. + * + * The underscore is automatically added if you are defining a prefix, for example: "prefix": "abc" will result in a key like abc_xxxxxxxxx + */ + prefix?: string; + /** + * @description The name for your Key. This is not customer facing. + * @example my key + */ + name?: string; + /** @description The raw key in plaintext. If provided, unkey encrypts this value and stores it securely. Provide either `hash` or `plaintext` */ + plaintext?: string; + /** @description Provide either `hash` or `plaintext` */ + hash?: { + /** @description The hashed and encoded key */ + value: string; + /** + * @description The algorithm for hashing and encoding, currently only sha256 and base64 are supported + * @enum {string} + */ + variant: "sha256_base64"; + }; + /** + * @description The first 4 characters of the key. If a prefix is used, it should be the prefix plus 4 characters. + * @example unkey_32kq + */ + start?: string; + /** + * @description Your user’s Id. This will provide a link between Unkey and your customer record. + * When validating a key, we will return this back to you, so you can clearly identify your user from their api key. + * @example team_123 + */ + ownerId?: string; + /** + * @description This is a place for dynamic meta data, anything that feels useful for you should go here + * @example { + * "billingTier": "PRO", + * "trialEnds": "2023-06-16T17:16:37.161Z" + * } + */ + meta?: { + [key: string]: unknown; + }; + /** + * @description A list of roles that this key should have. If the role does not exist, an error is thrown + * @example [ + * "admin", + * "finance" + * ] + */ + roles?: string[]; + /** + * @description A list of permissions that this key should have. If the permission does not exist, an error is thrown + * @example [ + * "domains.create_record", + * "say_hello" + * ] + */ + permissions?: string[]; + /** + * @description You can auto expire keys by providing a unix timestamp in milliseconds. Once Keys expire they will automatically be disabled and are no longer valid unless you enable them again. + * @example 1623869797161 + */ + expires?: number; + /** + * @description You can limit the number of requests a key can make. Once a key reaches 0 remaining requests, it will automatically be disabled and is no longer valid unless you update it. + * @example 1000 + */ + remaining?: number; + /** + * @description Unkey enables you to refill verifications for each key at regular intervals. + * @example { + * "interval": "daily", + * "amount": 100 + * } + */ + refill?: { + /** + * @description Unkey will automatically refill verifications at the set interval. + * @enum {string} + */ + interval: "daily" | "monthly"; + /** @description The number of verifications to refill for each occurrence is determined individually for each key. */ + amount: number; + }; + /** + * @description Unkey comes with per-key fixed-window ratelimiting out of the box. + * @example { + * "type": "fast", + * "limit": 10, + * "duration": 60000 + * } + */ + ratelimit?: { + /** + * @description Async will return a response immediately, lowering latency at the cost of accuracy. + * @default true + */ + async?: boolean; + /** + * @deprecated + * @description Deprecated, use `async`. Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. + * @default fast + * @enum {string} + */ + type?: "fast" | "consistent"; + /** @description The total amount of requests in a given interval. */ + limit: number; + /** + * @description The window duration in milliseconds + * @example 60000 + */ + duration: number; + /** + * @deprecated + * @description How many tokens to refill during each refillInterval. + */ + refillRate?: number; + /** + * @deprecated + * @description The refill timeframe, in milliseconds. + */ + refillInterval?: number; + }; + /** + * @description Sets if key is enabled or disabled. Disabled keys are not valid. + * @default true + * @example false + */ + enabled?: boolean; + /** + * @description Environments allow you to divide your keyspace. + * + * Some applications like Stripe, Clerk, WorkOS and others have a concept of "live" and "test" keys to + * give the developer a way to develop their own application without the risk of modifying real world + * resources. + * + * When you set an environment, we will return it back to you when validating the key, so you can + * handle it correctly. + */ + environment?: string; + })[]; }; }; }; @@ -3183,22 +3166,22 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the permission - * @example perm_123 - */ - id: string; - /** - * @description The name of the permission. - * @example domain.record.manager - */ - name: string; - /** - * @description The description of what this permission does. This is just for your team, your users will not see this. - * @example Can manage dns records - */ - description?: string; - }[]; + /** + * @description The id of the permission + * @example perm_123 + */ + id: string; + /** + * @description The name of the permission. + * @example domain.record.manager + */ + name: string; + /** + * @description The description of what this permission does. This is just for your team, your users will not see this. + * @example Can manage dns records + */ + description?: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -3461,22 +3444,22 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the role - * @example role_1234 - */ - id: string; - /** - * @description The name of the role. - * @example domain.record.manager - */ - name: string; - /** - * @description The description of what this role does. This is just for your team, your users will not see this. - * @example Can manage dns records - */ - description?: string; - }[]; + /** + * @description The id of the role + * @example role_1234 + */ + id: string; + /** + * @description The name of the role. + * @example domain.record.manager + */ + name: string; + /** + * @description The description of what this role does. This is just for your team, your users will not see this. + * @example Can manage dns records + */ + description?: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -3550,22 +3533,22 @@ export interface operations { * When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ ratelimits?: { - /** - * @description The name of this limit. You will need to use this again when verifying a key. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** + * @description The name of this limit. You will need to use this again when verifying a key. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }; }; }; @@ -3648,22 +3631,22 @@ export interface operations { }; /** @description When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ ratelimits: { - /** - * @description The name of this limit. You will need to use this again when verifying a key. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** + * @description The name of this limit. You will need to use this again when verifying a key. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }; }; }; @@ -3726,29 +3709,29 @@ export interface operations { "application/json": { /** @description A list of identities. */ identities: { - /** @description The id of this identity. Used to interact with unkey's API */ - id: string; - /** @description The id in your system */ - externalId: string; - /** @description When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ - ratelimits: { - /** - * @description The name of this limit. You will need to use this again when verifying a key. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; + /** @description The id of this identity. Used to interact with unkey's API */ + id: string; + /** @description The id in your system */ + externalId: string; + /** @description When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ + ratelimits: { + /** + * @description The name of this limit. You will need to use this again when verifying a key. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }[]; - }[]; /** * @description The cursor to use for the next page of results, if no cursor is returned, there are no more results * @example eyJrZXkiOiJrZXlfMTIzNCJ9 @@ -3841,22 +3824,22 @@ export interface operations { * When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ ratelimits?: { - /** - * @description The name of this limit. You will need to use this again when verifying a key. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** + * @description The name of this limit. You will need to use this again when verifying a key. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }; }; }; @@ -3885,22 +3868,22 @@ export interface operations { [key: string]: unknown; }; ratelimits: { - /** - * @description The name of this limit. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** + * @description The name of this limit. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }; }; }; @@ -4262,15 +4245,7 @@ export interface operations { * @example NOT_FOUND * @enum {string} */ - code?: - | "NOT_FOUND" - | "FORBIDDEN" - | "USAGE_EXCEEDED" - | "RATE_LIMITED" - | "UNAUTHORIZED" - | "DISABLED" - | "INSUFFICIENT_PERMISSIONS" - | "EXPIRED"; + code?: "NOT_FOUND" | "FORBIDDEN" | "USAGE_EXCEEDED" | "RATE_LIMITED" | "UNAUTHORIZED" | "DISABLED" | "INSUFFICIENT_PERMISSIONS" | "EXPIRED"; }; }; }; From a0d8e88bd9cd4fbfcf6b8cb71f5552d3335f77fd Mon Sep 17 00:00:00 2001 From: RajuGangitla Date: Tue, 8 Oct 2024 16:53:09 +0000 Subject: [PATCH 2/4] fixed issue comments --- .../[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx index 329d8b50ea..eaf4d38ea1 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx @@ -66,7 +66,7 @@ export default function PermissionTree({ roles }: PermissionTreeProps) { onOpenChange={(open) => { setOpenRoles(prev => open - ? [...prev, role.id] + ? prev.includes(role.id) ? prev : [...prev, role.id] : prev.filter(id => id !== role.id) ); }} @@ -74,13 +74,13 @@ export default function PermissionTree({ roles }: PermissionTreeProps) { - + -
{role.name}
+ {role.name}
-
{role.name}
+ {role.name}
From 6846063bd03d11ff158c22df340c9174dfa16b23 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:58:22 +0000 Subject: [PATCH 3/4] [autofix.ci] apply automated fixes --- .../[apiId]/keys/[keyAuthId]/[keyId]/page.tsx | 22 +- .../[keyAuthId]/[keyId]/permission-list.tsx | 182 +-- apps/dashboard/app/layout.tsx | 4 +- apps/engineering/app/layout.tsx | 4 +- apps/planetfall/app/layout.tsx | 4 +- apps/workflows/app/layout.tsx | 4 +- packages/api/src/openapi.d.ts | 1133 +++++++++-------- 7 files changed, 687 insertions(+), 666 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx index a9ae46cbaf..4c8b3b67cb 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx @@ -3,6 +3,7 @@ import Link from "next/link"; import { type Interval, IntervalSelect } from "@/app/(app)/apis/[apiId]/select"; import { CreateNewPermission } from "@/app/(app)/authorization/permissions/create-new-permission"; +import type { NestedPermissions } from "@/app/(app)/authorization/roles/[roleId]/tree"; import { CreateNewRole } from "@/app/(app)/authorization/roles/create-new-role"; import { StackedColumnChart } from "@/components/dashboard/charts"; import { EmptyPlaceholder } from "@/components/dashboard/empty-placeholder"; @@ -11,7 +12,7 @@ import { Button, buttonVariants } from "@/components/ui/button"; import { Card, CardContent, CardHeader } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { getTenantId } from "@/lib/auth"; -import { and, db, eq, isNull, Role, schema } from "@/lib/db"; +import { and, db, eq, isNull, schema } from "@/lib/db"; import { formatNumber } from "@/lib/fmt"; import { getLastUsed, @@ -23,11 +24,8 @@ import { cn } from "@/lib/utils"; import { BarChart, Minus } from "lucide-react"; import ms from "ms"; import { notFound } from "next/navigation"; -import { Chart } from "./chart"; -import { VerificationTable } from "./verification-table"; -import RolePermissionsTree from "./permission-list"; -import { NestedPermissions } from "@/app/(app)/authorization/roles/[roleId]/tree"; import PermissionTree from "./permission-list"; +import { VerificationTable } from "./verification-table"; export default async function APIKeyDetailPage(props: { params: { @@ -75,7 +73,6 @@ export default async function APIKeyDetailPage(props: { }, }); - if (!key || key.workspace.tenantId !== tenantId) { return notFound(); } @@ -161,7 +158,6 @@ export default async function APIKeyDetailPage(props: { } const roleTee = key.workspace.roles.map((role) => { - const nested: NestedPermissions = {}; for (const permission of key.workspace.permissions) { let n = nested; @@ -182,18 +178,16 @@ export default async function APIKeyDetailPage(props: { n = n[p].permissions; } } - let data = { + const data = { id: role.id, name: role.name, description: role.description, keyId: key.id, active: key.roles.some((keyRole) => keyRole.roleId === role.id), - nestedPermissions: nested - } - return data - }) - - + nestedPermissions: nested, + }; + return data; + }); return (
diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx index eaf4d38ea1..a22e3fdac9 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/permission-list.tsx @@ -1,111 +1,113 @@ -"use client" -import React, { useState, useEffect } from 'react'; +"use client"; +import { RecursivePermission } from "@/app/(app)/authorization/roles/[roleId]/tree"; +import { CopyButton } from "@/components/dashboard/copy-button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible"; import { Label } from "@/components/ui/label"; import { Switch } from "@/components/ui/switch"; -import { RecursivePermission } from '@/app/(app)/authorization/roles/[roleId]/tree'; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; -import { CopyButton } from '@/components/dashboard/copy-button'; -import { RoleToggle } from './role-toggle'; -import { ChevronRight } from 'lucide-react'; +import { ChevronRight } from "lucide-react"; +import { useEffect, useState } from "react"; +import { RoleToggle } from "./role-toggle"; export type NestedPermission = { - id: string; - checked: boolean; - description: string | null; - name: string; - part: string; - path: string; - permissions: NestedPermissions; + id: string; + checked: boolean; + description: string | null; + name: string; + part: string; + path: string; + permissions: NestedPermissions; }; export type NestedPermissions = Record; export type Role = { - id: string; - name: string; - keyId: string - active: boolean - description: string | null; - nestedPermissions: NestedPermissions; + id: string; + name: string; + keyId: string; + active: boolean; + description: string | null; + nestedPermissions: NestedPermissions; }; type PermissionTreeProps = { - roles: Role[]; + roles: Role[]; }; - export default function PermissionTree({ roles }: PermissionTreeProps) { - const [openAll, setOpenAll] = useState(false); - const [openRoles, setOpenRoles] = useState([]); + const [openAll, setOpenAll] = useState(false); + const [openRoles, setOpenRoles] = useState([]); - useEffect(() => { - setOpenRoles(openAll ? roles.map(role => role.id) : []); - }, [openAll, roles]); + useEffect(() => { + setOpenRoles(openAll ? roles.map((role) => role.id) : []); + }, [openAll, roles]); - return ( - - -
- Permissions -
-
- - -
-
+ return ( + + +
+ Permissions +
+
+ + +
+
- - {roles.map(role => { - const isOpen = openRoles.includes(role.id); - return ( - { - setOpenRoles(prev => - open - ? prev.includes(role.id) ? prev : [...prev, role.id] - : prev.filter(id => id !== role.id) - ); - }} - > - - - - - - {role.name} - - -
- {role.name} -
- -
-
-
-
- -
- -
- {Object.entries(role.nestedPermissions).map(([k, p]) => ( - - ))} -
-
-
- ); - })} -
-
- ); -} \ No newline at end of file + + {roles.map((role) => { + const isOpen = openRoles.includes(role.id); + return ( + { + setOpenRoles((prev) => + open + ? prev.includes(role.id) + ? prev + : [...prev, role.id] + : prev.filter((id) => id !== role.id), + ); + }} + > + + + + + + {role.name} + + +
+ + {role.name} + +
+ +
+
+
+
+
+ +
+ {Object.entries(role.nestedPermissions).map(([k, p]) => ( + + ))} +
+
+
+ ); + })} +
+
+ ); +} diff --git a/apps/dashboard/app/layout.tsx b/apps/dashboard/app/layout.tsx index 17dba12566..08263a8392 100644 --- a/apps/dashboard/app/layout.tsx +++ b/apps/dashboard/app/layout.tsx @@ -15,8 +15,8 @@ import { ThemeProvider } from "./theme-provider"; const inter = Inter({ subsets: ["latin"], variable: "--font-inter", - display: 'swap', - adjustFontFallback: false + display: "swap", + adjustFontFallback: false, }); const pangea = localFont({ diff --git a/apps/engineering/app/layout.tsx b/apps/engineering/app/layout.tsx index a9d8d41c4e..885b7a96cb 100644 --- a/apps/engineering/app/layout.tsx +++ b/apps/engineering/app/layout.tsx @@ -6,8 +6,8 @@ import "./global.css"; const inter = Inter({ subsets: ["latin"], - display: 'swap', - adjustFontFallback: false + display: "swap", + adjustFontFallback: false, }); export default function Layout({ children }: { children: ReactNode }) { diff --git a/apps/planetfall/app/layout.tsx b/apps/planetfall/app/layout.tsx index 4fa62083e4..a0fe67662f 100644 --- a/apps/planetfall/app/layout.tsx +++ b/apps/planetfall/app/layout.tsx @@ -4,8 +4,8 @@ import "./globals.css"; const inter = Inter({ subsets: ["latin"], - display: 'swap', - adjustFontFallback: false + display: "swap", + adjustFontFallback: false, }); export const metadata: Metadata = { diff --git a/apps/workflows/app/layout.tsx b/apps/workflows/app/layout.tsx index 26fb26f5b7..106f067c15 100644 --- a/apps/workflows/app/layout.tsx +++ b/apps/workflows/app/layout.tsx @@ -3,8 +3,8 @@ import { Inter } from "next/font/google"; const inter = Inter({ subsets: ["latin"], - display: 'swap', - adjustFontFallback: false + display: "swap", + adjustFontFallback: false, }); export const metadata: Metadata = { diff --git a/packages/api/src/openapi.d.ts b/packages/api/src/openapi.d.ts index b8908d1d73..ce8cfafe72 100644 --- a/packages/api/src/openapi.d.ts +++ b/packages/api/src/openapi.d.ts @@ -3,11 +3,14 @@ * Do not make direct changes to the file. */ - /** OneOf type helpers */ type Without = { [P in Exclude]?: never }; -type XOR = (T | U) extends object ? (Without & U) | (Without & T) : T | U; -type OneOf = T extends [infer Only] ? Only : T extends [infer A, infer B, ...infer Rest] ? OneOf<[XOR, ...Rest]> : never; +type XOR = T | U extends object ? (Without & U) | (Without & T) : T | U; +type OneOf = T extends [infer Only] + ? Only + : T extends [infer A, infer B, ...infer Rest] + ? OneOf<[XOR, ...Rest]> + : never; export interface paths { "/v1/liveness": { @@ -521,7 +524,16 @@ export interface components { * * @enum {string} */ - code: "VALID" | "NOT_FOUND" | "FORBIDDEN" | "USAGE_EXCEEDED" | "RATE_LIMITED" | "UNAUTHORIZED" | "DISABLED" | "INSUFFICIENT_PERMISSIONS" | "EXPIRED"; + code: + | "VALID" + | "NOT_FOUND" + | "FORBIDDEN" + | "USAGE_EXCEEDED" + | "RATE_LIMITED" + | "UNAUTHORIZED" + | "DISABLED" + | "INSUFFICIENT_PERMISSIONS" + | "EXPIRED"; /** @description Sets the key to be enabled or disabled. Disabled keys will not verify. */ enabled?: boolean; /** @@ -547,11 +559,18 @@ export interface components { }; }; /** @description A query for which permissions you require */ - PermissionQuery: OneOf<[string, { - and: components["schemas"]["PermissionQuery"][]; - }, { - or: components["schemas"]["PermissionQuery"][]; - }, null]>; + PermissionQuery: OneOf< + [ + string, + { + and: components["schemas"]["PermissionQuery"][]; + }, + { + or: components["schemas"]["PermissionQuery"][]; + }, + null, + ] + >; V1KeysVerifyKeyRequest: { /** * @description The id of the api where the key belongs to. This is optional for now but will be required soon. @@ -596,21 +615,21 @@ export interface components { * ] */ ratelimits?: { - /** - * @description The name of the ratelimit. - * @example tokens - */ - name: string; - /** - * @description Optionally override how expensive this operation is and how many tokens are deducted from the current limit. - * @default 1 - */ - cost?: number; - /** @description Optionally override the limit. */ - limit?: number; - /** @description Optionally override the ratelimit window duration. */ - duration?: number; - }[]; + /** + * @description The name of the ratelimit. + * @example tokens + */ + name: string; + /** + * @description Optionally override how expensive this operation is and how many tokens are deducted from the current limit. + * @default 1 + */ + cost?: number; + /** @description Optionally override the limit. */ + limit?: number; + /** @description Optionally override the ratelimit window duration. */ + duration?: number; + }[]; }; ErrDeleteProtected: { error: { @@ -636,8 +655,7 @@ export interface components { }; }; responses: never; - parameters: { - }; + parameters: {}; requestBodies: never; headers: never; pathItems: never; @@ -648,7 +666,6 @@ export type $defs = Record; export type external = Record; export interface operations { - "v1.liveness": { responses: { /** @description The configured services and their status */ @@ -1293,7 +1310,7 @@ export interface operations { * "refillInterval": 60 * } */ - ratelimit?: ({ + ratelimit?: { /** * @deprecated * @description Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. @@ -1325,7 +1342,7 @@ export interface operations { * This field will become required in a future version. */ duration?: number; - }) | null; + } | null; /** * @description The number of requests that can be made with this key before it becomes invalid. Set `null` to disable. * @example 1000 @@ -1338,7 +1355,7 @@ export interface operations { * "amount": 100 * } */ - refill?: ({ + refill?: { /** * @description Unkey will automatically refill verifications at the set interval. If null is used the refill functionality will be removed from the key. * @enum {string} @@ -1346,7 +1363,7 @@ export interface operations { interval: "daily" | "monthly"; /** @description The amount of verifications to refill for each occurrence is determined individually for each key. */ amount: number; - }) | null; + } | null; /** * @description Set if key is enabled or disabled. If disabled, the key cannot be used to verify. * @example true @@ -1369,16 +1386,16 @@ export interface operations { * ] */ roles?: { - /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; /** * @description The permissions you want to set for this key. This overwrites all existing permissions. * Setting permissions requires the `rbac.*.add_permission_to_key` permission. @@ -1396,16 +1413,16 @@ export interface operations { * ] */ permissions?: { - /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1555,27 +1572,27 @@ export interface operations { content: { "application/json": { verifications: { - /** - * @description The timestamp of the usage data - * @example 1620000000000 - */ - time: number; - /** - * @description The number of successful requests - * @example 100 - */ - success: number; - /** - * @description The number of requests that were rate limited - * @example 10 - */ - rateLimited: number; - /** - * @description The number of requests that exceeded the usage limit - * @example 0 - */ - usageExceeded: number; - }[]; + /** + * @description The timestamp of the usage data + * @example 1620000000000 + */ + time: number; + /** + * @description The number of successful requests + * @example 100 + */ + success: number; + /** + * @description The number of requests that were rate limited + * @example 10 + */ + rateLimited: number; + /** + * @description The number of requests that exceeded the usage limit + * @example 0 + */ + usageExceeded: number; + }[]; }; }; }; @@ -1631,16 +1648,16 @@ export interface operations { keyId: string; /** @description The permissions you want to add to this key */ permissions: { - /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1649,17 +1666,17 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the permission. This is used internally - * @example perm_123 - */ - id: string; - /** - * @description The name of the permission - * @example dns.record.create - */ - name: string; - }[]; + /** + * @description The id of the permission. This is used internally + * @example perm_123 + */ + id: string; + /** + * @description The name of the permission + * @example dns.record.create + */ + name: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -1724,11 +1741,11 @@ export interface operations { * ] */ permissions: { - /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - }[]; + /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + }[]; }; }; }; @@ -1806,16 +1823,16 @@ export interface operations { * ] */ permissions: { - /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the permission. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the permission via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating permissions requires your root key to have the `rbac.*.create_permission` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1824,17 +1841,17 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the permission. This is used internally - * @example perm_123 - */ - id: string; - /** - * @description The name of the permission - * @example dns.record.create - */ - name: string; - }[]; + /** + * @description The id of the permission. This is used internally + * @example perm_123 + */ + id: string; + /** + * @description The name of the permission + * @example dns.record.create + */ + name: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -1904,16 +1921,16 @@ export interface operations { * ] */ roles: { - /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -1922,17 +1939,17 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the role. This is used internally - * @example role_123 - */ - id: string; - /** - * @description The name of the role - * @example dns.record.create - */ - name: string; - }[]; + /** + * @description The id of the role. This is used internally + * @example role_123 + */ + id: string; + /** + * @description The name of the role + * @example dns.record.create + */ + name: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -1997,11 +2014,11 @@ export interface operations { * ] */ roles: { - /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - }[]; + /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + }[]; }; }; }; @@ -2079,16 +2096,16 @@ export interface operations { * ] */ roles: { - /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ - id?: string; - /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ - name?: string; - /** - * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. - * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected - */ - create?: boolean; - }[]; + /** @description The id of the role. Provide either `id` or `name`. If both are provided `id` is used. */ + id?: string; + /** @description Identify the role via its name. Provide either `id` or `name`. If both are provided `id` is used. */ + name?: string; + /** + * @description Set to true to automatically create the permissions they do not exist yet. Only works when specifying `name`. + * Autocreating roles requires your root key to have the `rbac.*.create_role` permission, otherwise the request will get rejected + */ + create?: boolean; + }[]; }; }; }; @@ -2097,17 +2114,17 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the role. This is used internally - * @example role_123 - */ - id: string; - /** - * @description The name of the role - * @example dns.record.create - */ - name: string; - }[]; + /** + * @description The id of the role. This is used internally + * @example role_123 + */ + id: string; + /** + * @description The name of the role + * @example dns.record.create + */ + name: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -2556,26 +2573,26 @@ export interface operations { * ] */ resources?: { - /** - * @description The type of resource - * @example organization - */ - type: string; - /** - * @description The unique identifier for the resource - * @example org_123 - */ - id: string; - /** - * @description A human readable name for this resource - * @example unkey - */ - name?: string; - /** @description Attach any metadata to this resources */ - meta?: { - [key: string]: unknown; - }; - }[]; + /** + * @description The type of resource + * @example organization + */ + type: string; + /** + * @description The unique identifier for the resource + * @example org_123 + */ + id: string; + /** + * @description A human readable name for this resource + * @example unkey + */ + name?: string; + /** @description Attach any metadata to this resources */ + meta?: { + [key: string]: unknown; + }; + }[]; }; }; }; @@ -2653,33 +2670,245 @@ export interface operations { "v1.migrations.createKeys": { requestBody: { content: { - "application/json": ({ - /** - * @description Choose an `API` where this key should be created. - * @example api_123 - */ - apiId: string; + "application/json": { + /** + * @description Choose an `API` where this key should be created. + * @example api_123 + */ + apiId: string; + /** + * @description To make it easier for your users to understand which product an api key belongs to, you can add prefix them. + * + * For example Stripe famously prefixes their customer ids with cus_ or their api keys with sk_live_. + * + * The underscore is automatically added if you are defining a prefix, for example: "prefix": "abc" will result in a key like abc_xxxxxxxxx + */ + prefix?: string; + /** + * @description The name for your Key. This is not customer facing. + * @example my key + */ + name?: string; + /** @description The raw key in plaintext. If provided, unkey encrypts this value and stores it securely. Provide either `hash` or `plaintext` */ + plaintext?: string; + /** @description Provide either `hash` or `plaintext` */ + hash?: { + /** @description The hashed and encoded key */ + value: string; /** - * @description To make it easier for your users to understand which product an api key belongs to, you can add prefix them. - * - * For example Stripe famously prefixes their customer ids with cus_ or their api keys with sk_live_. - * - * The underscore is automatically added if you are defining a prefix, for example: "prefix": "abc" will result in a key like abc_xxxxxxxxx + * @description The algorithm for hashing and encoding, currently only sha256 and base64 are supported + * @enum {string} */ - prefix?: string; + variant: "sha256_base64"; + }; + /** + * @description The first 4 characters of the key. If a prefix is used, it should be the prefix plus 4 characters. + * @example unkey_32kq + */ + start?: string; + /** + * @description Your user’s Id. This will provide a link between Unkey and your customer record. + * When validating a key, we will return this back to you, so you can clearly identify your user from their api key. + * @example team_123 + */ + ownerId?: string; + /** + * @description This is a place for dynamic meta data, anything that feels useful for you should go here + * @example { + * "billingTier": "PRO", + * "trialEnds": "2023-06-16T17:16:37.161Z" + * } + */ + meta?: { + [key: string]: unknown; + }; + /** + * @description A list of roles that this key should have. If the role does not exist, an error is thrown + * @example [ + * "admin", + * "finance" + * ] + */ + roles?: string[]; + /** + * @description A list of permissions that this key should have. If the permission does not exist, an error is thrown + * @example [ + * "domains.create_record", + * "say_hello" + * ] + */ + permissions?: string[]; + /** + * @description You can auto expire keys by providing a unix timestamp in milliseconds. Once Keys expire they will automatically be disabled and are no longer valid unless you enable them again. + * @example 1623869797161 + */ + expires?: number; + /** + * @description You can limit the number of requests a key can make. Once a key reaches 0 remaining requests, it will automatically be disabled and is no longer valid unless you update it. + * @example 1000 + */ + remaining?: number; + /** + * @description Unkey enables you to refill verifications for each key at regular intervals. + * @example { + * "interval": "daily", + * "amount": 100 + * } + */ + refill?: { /** - * @description The name for your Key. This is not customer facing. - * @example my key + * @description Unkey will automatically refill verifications at the set interval. + * @enum {string} */ - name?: string; - /** @description The raw key in plaintext. If provided, unkey encrypts this value and stores it securely. Provide either `hash` or `plaintext` */ - plaintext?: string; - /** @description Provide either `hash` or `plaintext` */ - hash?: { - /** @description The hashed and encoded key */ - value: string; - /** - * @description The algorithm for hashing and encoding, currently only sha256 and base64 are supported + interval: "daily" | "monthly"; + /** @description The number of verifications to refill for each occurrence is determined individually for each key. */ + amount: number; + }; + /** + * @description Unkey comes with per-key ratelimiting out of the box. + * @example { + * "type": "fast", + * "limit": 10, + * "refillRate": 1, + * "refillInterval": 60 + * } + */ + ratelimit?: { + /** + * @description Async will return a response immediately, lowering latency at the cost of accuracy. + * @default false + */ + async?: boolean; + /** + * @deprecated + * @description Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. + * @default fast + * @enum {string} + */ + type?: "fast" | "consistent"; + /** @description The total amount of burstable requests. */ + limit: number; + /** + * @deprecated + * @description How many tokens to refill during each refillInterval. + */ + refillRate: number; + /** + * @deprecated + * @description Determines the speed at which tokens are refilled, in milliseconds. + */ + refillInterval: number; + }; + /** + * @description Sets if key is enabled or disabled. Disabled keys are not valid. + * @default true + * @example false + */ + enabled?: boolean; + /** + * @description Environments allow you to divide your keyspace. + * + * Some applications like Stripe, Clerk, WorkOS and others have a concept of "live" and "test" keys to + * give the developer a way to develop their own application without the risk of modifying real world + * resources. + * + * When you set an environment, we will return it back to you when validating the key, so you can + * handle it correctly. + */ + environment?: string; + }[]; + }; + }; + responses: { + /** @description The key ids of all created keys */ + 200: { + content: { + "application/json": { + /** + * @description The ids of the keys. This is not a secret and can be stored as a reference if you wish. You need the keyId to update or delete a key later. + * @example [ + * "key_123", + * "key_456" + * ] + */ + keyIds: string[]; + }; + }; + }; + /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ + 400: { + content: { + "application/json": components["schemas"]["ErrBadRequest"]; + }; + }; + /** @description Although the HTTP standard specifies "unauthorized", semantically this response means "unauthenticated". That is, the client must authenticate itself to get the requested response. */ + 401: { + content: { + "application/json": components["schemas"]["ErrUnauthorized"]; + }; + }; + /** @description The client does not have access rights to the content; that is, it is unauthorized, so the server is refusing to give the requested resource. Unlike 401 Unauthorized, the client's identity is known to the server. */ + 403: { + content: { + "application/json": components["schemas"]["ErrForbidden"]; + }; + }; + /** @description The server cannot find the requested resource. In the browser, this means the URL is not recognized. In an API, this can also mean that the endpoint is valid but the resource itself does not exist. Servers may also send this response instead of 403 Forbidden to hide the existence of a resource from an unauthorized client. This response code is probably the most well known due to its frequent occurrence on the web. */ + 404: { + content: { + "application/json": components["schemas"]["ErrNotFound"]; + }; + }; + /** @description This response is sent when a request conflicts with the current state of the server. */ + 409: { + content: { + "application/json": components["schemas"]["ErrConflict"]; + }; + }; + /** @description The user has sent too many requests in a given amount of time ("rate limiting") */ + 429: { + content: { + "application/json": components["schemas"]["ErrTooManyRequests"]; + }; + }; + /** @description The server has encountered a situation it does not know how to handle. */ + 500: { + content: { + "application/json": components["schemas"]["ErrInternalServerError"]; + }; + }; + }; + }; + "v1.migrations.enqueueKeys": { + requestBody: { + content: { + "application/json": { + /** @description Contact support@unkey.dev to receive your migration id. */ + migrationId: string; + /** @description The id of the api, you want to migrate keys to */ + apiId: string; + keys: { + /** + * @description To make it easier for your users to understand which product an api key belongs to, you can add prefix them. + * + * For example Stripe famously prefixes their customer ids with cus_ or their api keys with sk_live_. + * + * The underscore is automatically added if you are defining a prefix, for example: "prefix": "abc" will result in a key like abc_xxxxxxxxx + */ + prefix?: string; + /** + * @description The name for your Key. This is not customer facing. + * @example my key + */ + name?: string; + /** @description The raw key in plaintext. If provided, unkey encrypts this value and stores it securely. Provide either `hash` or `plaintext` */ + plaintext?: string; + /** @description Provide either `hash` or `plaintext` */ + hash?: { + /** @description The hashed and encoded key */ + value: string; + /** + * @description The algorithm for hashing and encoding, currently only sha256 and base64 are supported * @enum {string} */ variant: "sha256_base64"; @@ -2748,39 +2977,43 @@ export interface operations { amount: number; }; /** - * @description Unkey comes with per-key ratelimiting out of the box. + * @description Unkey comes with per-key fixed-window ratelimiting out of the box. * @example { * "type": "fast", * "limit": 10, - * "refillRate": 1, - * "refillInterval": 60 + * "duration": 60000 * } */ ratelimit?: { /** * @description Async will return a response immediately, lowering latency at the cost of accuracy. - * @default false + * @default true */ async?: boolean; /** * @deprecated - * @description Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. + * @description Deprecated, use `async`. Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. * @default fast * @enum {string} */ type?: "fast" | "consistent"; - /** @description The total amount of burstable requests. */ + /** @description The total amount of requests in a given interval. */ limit: number; + /** + * @description The window duration in milliseconds + * @example 60000 + */ + duration: number; /** * @deprecated * @description How many tokens to refill during each refillInterval. */ - refillRate: number; + refillRate?: number; /** * @deprecated - * @description Determines the speed at which tokens are refilled, in milliseconds. + * @description The refill timeframe, in milliseconds. */ - refillInterval: number; + refillInterval?: number; }; /** * @description Sets if key is enabled or disabled. Disabled keys are not valid. @@ -2799,223 +3032,7 @@ export interface operations { * handle it correctly. */ environment?: string; - })[]; - }; - }; - responses: { - /** @description The key ids of all created keys */ - 200: { - content: { - "application/json": { - /** - * @description The ids of the keys. This is not a secret and can be stored as a reference if you wish. You need the keyId to update or delete a key later. - * @example [ - * "key_123", - * "key_456" - * ] - */ - keyIds: string[]; - }; - }; - }; - /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ - 400: { - content: { - "application/json": components["schemas"]["ErrBadRequest"]; - }; - }; - /** @description Although the HTTP standard specifies "unauthorized", semantically this response means "unauthenticated". That is, the client must authenticate itself to get the requested response. */ - 401: { - content: { - "application/json": components["schemas"]["ErrUnauthorized"]; - }; - }; - /** @description The client does not have access rights to the content; that is, it is unauthorized, so the server is refusing to give the requested resource. Unlike 401 Unauthorized, the client's identity is known to the server. */ - 403: { - content: { - "application/json": components["schemas"]["ErrForbidden"]; - }; - }; - /** @description The server cannot find the requested resource. In the browser, this means the URL is not recognized. In an API, this can also mean that the endpoint is valid but the resource itself does not exist. Servers may also send this response instead of 403 Forbidden to hide the existence of a resource from an unauthorized client. This response code is probably the most well known due to its frequent occurrence on the web. */ - 404: { - content: { - "application/json": components["schemas"]["ErrNotFound"]; - }; - }; - /** @description This response is sent when a request conflicts with the current state of the server. */ - 409: { - content: { - "application/json": components["schemas"]["ErrConflict"]; - }; - }; - /** @description The user has sent too many requests in a given amount of time ("rate limiting") */ - 429: { - content: { - "application/json": components["schemas"]["ErrTooManyRequests"]; - }; - }; - /** @description The server has encountered a situation it does not know how to handle. */ - 500: { - content: { - "application/json": components["schemas"]["ErrInternalServerError"]; - }; - }; - }; - }; - "v1.migrations.enqueueKeys": { - requestBody: { - content: { - "application/json": { - /** @description Contact support@unkey.dev to receive your migration id. */ - migrationId: string; - /** @description The id of the api, you want to migrate keys to */ - apiId: string; - keys: ({ - /** - * @description To make it easier for your users to understand which product an api key belongs to, you can add prefix them. - * - * For example Stripe famously prefixes their customer ids with cus_ or their api keys with sk_live_. - * - * The underscore is automatically added if you are defining a prefix, for example: "prefix": "abc" will result in a key like abc_xxxxxxxxx - */ - prefix?: string; - /** - * @description The name for your Key. This is not customer facing. - * @example my key - */ - name?: string; - /** @description The raw key in plaintext. If provided, unkey encrypts this value and stores it securely. Provide either `hash` or `plaintext` */ - plaintext?: string; - /** @description Provide either `hash` or `plaintext` */ - hash?: { - /** @description The hashed and encoded key */ - value: string; - /** - * @description The algorithm for hashing and encoding, currently only sha256 and base64 are supported - * @enum {string} - */ - variant: "sha256_base64"; - }; - /** - * @description The first 4 characters of the key. If a prefix is used, it should be the prefix plus 4 characters. - * @example unkey_32kq - */ - start?: string; - /** - * @description Your user’s Id. This will provide a link between Unkey and your customer record. - * When validating a key, we will return this back to you, so you can clearly identify your user from their api key. - * @example team_123 - */ - ownerId?: string; - /** - * @description This is a place for dynamic meta data, anything that feels useful for you should go here - * @example { - * "billingTier": "PRO", - * "trialEnds": "2023-06-16T17:16:37.161Z" - * } - */ - meta?: { - [key: string]: unknown; - }; - /** - * @description A list of roles that this key should have. If the role does not exist, an error is thrown - * @example [ - * "admin", - * "finance" - * ] - */ - roles?: string[]; - /** - * @description A list of permissions that this key should have. If the permission does not exist, an error is thrown - * @example [ - * "domains.create_record", - * "say_hello" - * ] - */ - permissions?: string[]; - /** - * @description You can auto expire keys by providing a unix timestamp in milliseconds. Once Keys expire they will automatically be disabled and are no longer valid unless you enable them again. - * @example 1623869797161 - */ - expires?: number; - /** - * @description You can limit the number of requests a key can make. Once a key reaches 0 remaining requests, it will automatically be disabled and is no longer valid unless you update it. - * @example 1000 - */ - remaining?: number; - /** - * @description Unkey enables you to refill verifications for each key at regular intervals. - * @example { - * "interval": "daily", - * "amount": 100 - * } - */ - refill?: { - /** - * @description Unkey will automatically refill verifications at the set interval. - * @enum {string} - */ - interval: "daily" | "monthly"; - /** @description The number of verifications to refill for each occurrence is determined individually for each key. */ - amount: number; - }; - /** - * @description Unkey comes with per-key fixed-window ratelimiting out of the box. - * @example { - * "type": "fast", - * "limit": 10, - * "duration": 60000 - * } - */ - ratelimit?: { - /** - * @description Async will return a response immediately, lowering latency at the cost of accuracy. - * @default true - */ - async?: boolean; - /** - * @deprecated - * @description Deprecated, use `async`. Fast ratelimiting doesn't add latency, while consistent ratelimiting is more accurate. - * @default fast - * @enum {string} - */ - type?: "fast" | "consistent"; - /** @description The total amount of requests in a given interval. */ - limit: number; - /** - * @description The window duration in milliseconds - * @example 60000 - */ - duration: number; - /** - * @deprecated - * @description How many tokens to refill during each refillInterval. - */ - refillRate?: number; - /** - * @deprecated - * @description The refill timeframe, in milliseconds. - */ - refillInterval?: number; - }; - /** - * @description Sets if key is enabled or disabled. Disabled keys are not valid. - * @default true - * @example false - */ - enabled?: boolean; - /** - * @description Environments allow you to divide your keyspace. - * - * Some applications like Stripe, Clerk, WorkOS and others have a concept of "live" and "test" keys to - * give the developer a way to develop their own application without the risk of modifying real world - * resources. - * - * When you set an environment, we will return it back to you when validating the key, so you can - * handle it correctly. - */ - environment?: string; - })[]; + }[]; }; }; }; @@ -3286,22 +3303,22 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the permission - * @example perm_123 - */ - id: string; - /** - * @description The name of the permission. - * @example domain.record.manager - */ - name: string; - /** - * @description The description of what this permission does. This is just for your team, your users will not see this. - * @example Can manage dns records - */ - description?: string; - }[]; + /** + * @description The id of the permission + * @example perm_123 + */ + id: string; + /** + * @description The name of the permission. + * @example domain.record.manager + */ + name: string; + /** + * @description The description of what this permission does. This is just for your team, your users will not see this. + * @example Can manage dns records + */ + description?: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -3564,22 +3581,22 @@ export interface operations { 200: { content: { "application/json": { - /** - * @description The id of the role - * @example role_1234 - */ - id: string; - /** - * @description The name of the role. - * @example domain.record.manager - */ - name: string; - /** - * @description The description of what this role does. This is just for your team, your users will not see this. - * @example Can manage dns records - */ - description?: string; - }[]; + /** + * @description The id of the role + * @example role_1234 + */ + id: string; + /** + * @description The name of the role. + * @example domain.record.manager + */ + name: string; + /** + * @description The description of what this role does. This is just for your team, your users will not see this. + * @example Can manage dns records + */ + description?: string; + }[]; }; }; /** @description The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing). */ @@ -3653,22 +3670,22 @@ export interface operations { * When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ ratelimits?: { - /** - * @description The name of this limit. You will need to use this again when verifying a key. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** + * @description The name of this limit. You will need to use this again when verifying a key. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }; }; }; @@ -3751,22 +3768,22 @@ export interface operations { }; /** @description When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ ratelimits: { - /** - * @description The name of this limit. You will need to use this again when verifying a key. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** + * @description The name of this limit. You will need to use this again when verifying a key. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }; }; }; @@ -3829,29 +3846,29 @@ export interface operations { "application/json": { /** @description A list of identities. */ identities: { - /** @description The id of this identity. Used to interact with unkey's API */ - id: string; - /** @description The id in your system */ - externalId: string; - /** @description When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ - ratelimits: { - /** - * @description The name of this limit. You will need to use this again when verifying a key. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** @description The id of this identity. Used to interact with unkey's API */ + id: string; + /** @description The id in your system */ + externalId: string; + /** @description When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ + ratelimits: { + /** + * @description The name of this limit. You will need to use this again when verifying a key. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; }[]; + }[]; /** * @description The cursor to use for the next page of results, if no cursor is returned, there are no more results * @example eyJrZXkiOiJrZXlfMTIzNCJ9 @@ -3944,22 +3961,22 @@ export interface operations { * When verifying keys, you can specify which limits you want to use and all keys attached to this identity, will share the limits. */ ratelimits?: { - /** - * @description The name of this limit. You will need to use this again when verifying a key. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** + * @description The name of this limit. You will need to use this again when verifying a key. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }; }; }; @@ -3988,22 +4005,22 @@ export interface operations { [key: string]: unknown; }; ratelimits: { - /** - * @description The name of this limit. - * @example tokens - */ - name: string; - /** - * @description How many requests may pass within a given window before requests are rejected. - * @example 10 - */ - limit: number; - /** - * @description The duration for each ratelimit window in milliseconds. - * @example 1000 - */ - duration: number; - }[]; + /** + * @description The name of this limit. + * @example tokens + */ + name: string; + /** + * @description How many requests may pass within a given window before requests are rejected. + * @example 10 + */ + limit: number; + /** + * @description The duration for each ratelimit window in milliseconds. + * @example 1000 + */ + duration: number; + }[]; }; }; }; @@ -4365,7 +4382,15 @@ export interface operations { * @example NOT_FOUND * @enum {string} */ - code?: "NOT_FOUND" | "FORBIDDEN" | "USAGE_EXCEEDED" | "RATE_LIMITED" | "UNAUTHORIZED" | "DISABLED" | "INSUFFICIENT_PERMISSIONS" | "EXPIRED"; + code?: + | "NOT_FOUND" + | "FORBIDDEN" + | "USAGE_EXCEEDED" + | "RATE_LIMITED" + | "UNAUTHORIZED" + | "DISABLED" + | "INSUFFICIENT_PERMISSIONS" + | "EXPIRED"; }; }; }; From f48eb86697bf99f7527c8d5536adcae6160694b1 Mon Sep 17 00:00:00 2001 From: RajuGangitla Date: Sun, 13 Oct 2024 09:15:48 +0000 Subject: [PATCH 4/4] removed font --- .../apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx | 13 ------------- apps/dashboard/app/layout.tsx | 2 -- apps/engineering/app/layout.tsx | 2 -- apps/planetfall/app/layout.tsx | 2 -- apps/workflows/app/layout.tsx | 2 -- 5 files changed, 21 deletions(-) diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx index 4c8b3b67cb..d17c24347f 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/[keyId]/page.tsx @@ -343,19 +343,6 @@ export default async function APIKeyDetailPage(props: {
- {/* ({ - ...r, - active: key.roles.some((keyRole) => keyRole.roleId === r.id), - }))} - permissions={key.workspace.permissions.map((p) => ({ - ...p, - active: transientPermissionIds.has(p.id), - }))} - /> */}
); diff --git a/apps/dashboard/app/layout.tsx b/apps/dashboard/app/layout.tsx index 08263a8392..09c23c7d3c 100644 --- a/apps/dashboard/app/layout.tsx +++ b/apps/dashboard/app/layout.tsx @@ -15,8 +15,6 @@ import { ThemeProvider } from "./theme-provider"; const inter = Inter({ subsets: ["latin"], variable: "--font-inter", - display: "swap", - adjustFontFallback: false, }); const pangea = localFont({ diff --git a/apps/engineering/app/layout.tsx b/apps/engineering/app/layout.tsx index 885b7a96cb..182e4dae01 100644 --- a/apps/engineering/app/layout.tsx +++ b/apps/engineering/app/layout.tsx @@ -6,8 +6,6 @@ import "./global.css"; const inter = Inter({ subsets: ["latin"], - display: "swap", - adjustFontFallback: false, }); export default function Layout({ children }: { children: ReactNode }) { diff --git a/apps/planetfall/app/layout.tsx b/apps/planetfall/app/layout.tsx index a0fe67662f..60570a4e29 100644 --- a/apps/planetfall/app/layout.tsx +++ b/apps/planetfall/app/layout.tsx @@ -4,8 +4,6 @@ import "./globals.css"; const inter = Inter({ subsets: ["latin"], - display: "swap", - adjustFontFallback: false, }); export const metadata: Metadata = { diff --git a/apps/workflows/app/layout.tsx b/apps/workflows/app/layout.tsx index 106f067c15..4e0ed72470 100644 --- a/apps/workflows/app/layout.tsx +++ b/apps/workflows/app/layout.tsx @@ -3,8 +3,6 @@ import { Inter } from "next/font/google"; const inter = Inter({ subsets: ["latin"], - display: "swap", - adjustFontFallback: false, }); export const metadata: Metadata = {