From e82fa3b9a5c282b9022a3786b2fc8cbe76dfaead Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Sun, 30 Nov 2025 17:36:10 -0800 Subject: [PATCH 1/2] feat: api keys --- frontend/src/app/user-dropdown.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/frontend/src/app/user-dropdown.tsx b/frontend/src/app/user-dropdown.tsx index 1e8d7a70fc..20aec6e7a3 100644 --- a/frontend/src/app/user-dropdown.tsx +++ b/frontend/src/app/user-dropdown.tsx @@ -77,6 +77,18 @@ export function UserDropdown() { Tokens ) : null} + {isMatchingProjectRoute ? ( + { + navigate({ + to: ".", + search: (old) => ({ ...old, modal: "api-keys" }), + }); + }} + > + API Keys + + ) : null} {clerk.organization ? ( { From bc1efb9b6552c4a620bf9c1d86abc7ff453a5f0c Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Sun, 30 Nov 2025 01:22:42 -0800 Subject: [PATCH 2/2] feat(frontend): create api key --- frontend/.env | 2 +- frontend/package.json | 2 +- .../data-providers/cloud-data-provider.tsx | 47 ++ frontend/src/app/dialogs/api-tokens-frame.tsx | 170 ++++++ .../app/dialogs/create-api-token-frame.tsx | 127 ++++ frontend/src/app/dialogs/tokens-frame.tsx | 134 ++++- .../src/app/forms/create-api-token-form.tsx | 98 ++++ frontend/src/app/layout.tsx | 26 +- .../src/app/publishable-token-code-group.tsx | 165 ++++++ frontend/src/app/use-dialog.tsx | 4 + frontend/src/app/user-dropdown.tsx | 24 - .../src/components/actors/data-provider.tsx | 28 +- frontend/src/queries/utils.ts | 2 +- frontend/src/routeTree.gen.ts | 26 + frontend/src/routes/_context/_cloud.tsx | 18 - .../ns.$namespace/connect.tsx | 216 +------ .../ns.$namespace/tokens.tsx | 546 ++++++++++++++++++ pnpm-lock.yaml | 10 +- 18 files changed, 1362 insertions(+), 283 deletions(-) create mode 100644 frontend/src/app/dialogs/api-tokens-frame.tsx create mode 100644 frontend/src/app/dialogs/create-api-token-frame.tsx create mode 100644 frontend/src/app/forms/create-api-token-form.tsx create mode 100644 frontend/src/app/publishable-token-code-group.tsx create mode 100644 frontend/src/routes/_context/_cloud/orgs.$organization/projects.$project/ns.$namespace/tokens.tsx diff --git a/frontend/.env b/frontend/.env index 195dbc717d..a01f6ea33f 100644 --- a/frontend/.env +++ b/frontend/.env @@ -1,5 +1,5 @@ VITE_APP_API_URL=http://localhost:43708/api -VITE_APP_CLOUD_API_URL=http://localhost:43708/api +VITE_APP_CLOUD_API_URL=http://localhost:3000 VITE_APP_ASSETS_URL=https://assets2.rivet.gg VITE_APP_CLERK_PUBLISHABLE_KEY=pk_test_Zmlyc3QtZG9ua2V5LTQuY2xlcmsuYWNjb3VudHMuZGV2JA VITE_APP_SENTRY_DSN="https://66a566505cfb4341732a3d350f2b87e2@o4504307129188352.ingest.sentry.io/4506435887366144" diff --git a/frontend/package.json b/frontend/package.json index 111eb521dd..633ef73254 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -57,7 +57,7 @@ "@radix-ui/react-toggle-group": "^1.1.11", "@radix-ui/react-tooltip": "^1.2.8", "@radix-ui/react-visually-hidden": "^1.2.3", - "@rivet-gg/cloud": "https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@bf2ebb2", + "@rivet-gg/cloud": "https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@11dea2c", "@rivet-gg/icons": "workspace:*", "@rivetkit/engine-api-full": "workspace:*", "@sentry/react": "^8.55.0", diff --git a/frontend/src/app/data-providers/cloud-data-provider.tsx b/frontend/src/app/data-providers/cloud-data-provider.tsx index 74591ac66c..27d30568c9 100644 --- a/frontend/src/app/data-providers/cloud-data-provider.tsx +++ b/frontend/src/app/data-providers/cloud-data-provider.tsx @@ -330,6 +330,53 @@ export const createProjectContext = ({ }, }); }, + // API Token methods + apiTokensQueryOptions() { + return queryOptions({ + queryKey: [{ organization, project }, "api-tokens"], + queryFn: async ({ signal: abortSignal }) => { + const response = await client.apiTokens.list( + project, + { org: organization }, + { abortSignal }, + ); + return response; + }, + }); + }, + createApiTokenMutationOptions(opts?: { + onSuccess?: (data: Rivet.CreateApiTokenResponse) => void; + }) { + return { + mutationKey: [{ organization, project }, "api-tokens", "create"], + mutationFn: async (data: { + name: string; + expiresAt?: string; + }) => { + const response = await client.apiTokens.create(project, { + name: data.name, + expiresAt: data.expiresAt, + org: organization, + }); + return response; + }, + onSuccess: opts?.onSuccess, + }; + }, + revokeApiTokenMutationOptions(opts?: { onSuccess?: () => void }) { + return { + mutationKey: [{ organization, project }, "api-tokens", "revoke"], + mutationFn: async (data: { apiTokenId: string }) => { + const response = await client.apiTokens.revoke( + project, + data.apiTokenId, + { org: organization }, + ); + return response; + }, + onSuccess: opts?.onSuccess, + }; + }, }; }; diff --git a/frontend/src/app/dialogs/api-tokens-frame.tsx b/frontend/src/app/dialogs/api-tokens-frame.tsx new file mode 100644 index 0000000000..33efc69f7c --- /dev/null +++ b/frontend/src/app/dialogs/api-tokens-frame.tsx @@ -0,0 +1,170 @@ +import { faPlus, faQuestionCircle, faTrash, Icon } from "@rivet-gg/icons"; +import { useMutation, useQuery } from "@tanstack/react-query"; +import { useRouteContext } from "@tanstack/react-router"; +import { HelpDropdown } from "@/app/help-dropdown"; +import { + Button, + type DialogContentProps, + Frame, + Skeleton, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components"; +import { queryClient } from "@/queries/global"; +import { useDialog } from "@/app/use-dialog"; + +interface ApiTokensFrameContentProps extends DialogContentProps {} + +export default function ApiTokensFrameContent({ + onClose, +}: ApiTokensFrameContentProps) { + const { dataProvider } = useRouteContext({ + from: "/_context/_cloud/orgs/$organization/projects/$project", + }); + + const { data, isLoading } = useQuery(dataProvider.apiTokensQueryOptions()); + + const { open: openCreateApiToken, dialog: createApiTokenDialog } = + useDialog.CreateApiToken({}); + + return ( + <> + + +
Cloud API Tokens
+ + + +
+ + Cloud API tokens provide programmatic access to the Rivet Cloud API. Keep + them secure and never share them publicly. + +
+ + {isLoading ? ( +
+ + + +
+ ) : ( + + + + Name + Token + Created + Expires + + + + + {data?.apiTokens.length === 0 ? ( + + + No Cloud API tokens yet. Create one to get started. + + + ) : ( + data?.apiTokens.map((apiToken) => ( + + )) + )} + + + + + + +
+ )} +
+ + + + {createApiTokenDialog} + + ); +} + +interface ApiTokenRowProps { + apiToken: { + id: string; + name: string; + createdAt: string; + expiresAt?: string; + revoked: boolean; + lastFourChars: string; + }; + dataProvider: ReturnType< + typeof useRouteContext<"/_context/_cloud/orgs/$organization/projects/$project"> + >["dataProvider"]; +} + +function ApiTokenRow({ apiToken, dataProvider }: ApiTokenRowProps) { + const { mutate: revoke, isPending } = useMutation( + dataProvider.revokeApiTokenMutationOptions({ + onSuccess: async () => { + await queryClient.invalidateQueries( + dataProvider.apiTokensQueryOptions(), + ); + }, + }), + ); + + const createdDate = new Date(apiToken.createdAt).toLocaleDateString(); + const expiresDate = apiToken.expiresAt + ? new Date(apiToken.expiresAt).toLocaleDateString() + : "Never"; + + return ( + + {apiToken.name} + + + cloud_api_...{apiToken.lastFourChars} + + + {createdDate} + {expiresDate} + + {!apiToken.revoked && ( + + )} + {apiToken.revoked && ( + Revoked + )} + + + ); +} diff --git a/frontend/src/app/dialogs/create-api-token-frame.tsx b/frontend/src/app/dialogs/create-api-token-frame.tsx new file mode 100644 index 0000000000..cc7342a13b --- /dev/null +++ b/frontend/src/app/dialogs/create-api-token-frame.tsx @@ -0,0 +1,127 @@ +import { useState } from "react"; +import { useMutation } from "@tanstack/react-query"; +import { useRouteContext } from "@tanstack/react-router"; +import { + Button, + type DialogContentProps, + DiscreteInput, + Flex, + Frame, + Label, +} from "@/components"; +import { queryClient } from "@/queries/global"; +import * as CreateApiTokenForm from "@/app/forms/create-api-token-form"; + +interface CreateApiTokenFrameContentProps extends DialogContentProps {} + +/** + * Convert duration string (e.g., "1y", "30d", "1h") to ISO 8601 timestamp + */ +function convertDurationToExpiresAt(duration: string): string | undefined { + if (duration === "never") { + return undefined; + } + + const now = new Date(); + const match = duration.match(/^(\d+)([mhdy])$/); + + if (!match) { + return undefined; + } + + const value = Number.parseInt(match[1], 10); + const unit = match[2]; + + switch (unit) { + case "m": + now.setMinutes(now.getMinutes() + value); + break; + case "h": + now.setHours(now.getHours() + value); + break; + case "d": + now.setDate(now.getDate() + value); + break; + case "y": + now.setFullYear(now.getFullYear() + value); + break; + } + + return now.toISOString(); +} + +export default function CreateApiTokenFrameContent({ + onClose, +}: CreateApiTokenFrameContentProps) { + const { dataProvider } = useRouteContext({ + from: "/_context/_cloud/orgs/$organization/projects/$project", + }); + const [createdToken, setCreatedToken] = useState(null); + + const { mutateAsync, isPending } = useMutation( + dataProvider.createApiTokenMutationOptions({ + onSuccess: async (data) => { + setCreatedToken(data.apiToken); + await queryClient.invalidateQueries( + dataProvider.apiTokensQueryOptions(), + ); + }, + }), + ); + + // Show the created token (only shown once!) + if (createdToken) { + return ( + <> + + Create Cloud API Token + + +
+ + +

+ This is the only time you'll see this token. Copy it now + and store it securely. +

+
+
+ + + + + ); + } + + return ( + { + await mutateAsync({ + name: values.name, + expiresAt: values.expiresIn ? convertDurationToExpiresAt(values.expiresIn) : undefined, + }); + }} + defaultValues={{ name: "", expiresIn: "1y" }} + > + + Create Cloud API Token + + + + + + + + + + Create + + + + + ); +} diff --git a/frontend/src/app/dialogs/tokens-frame.tsx b/frontend/src/app/dialogs/tokens-frame.tsx index 60b1908151..4447fe43ab 100644 --- a/frontend/src/app/dialogs/tokens-frame.tsx +++ b/frontend/src/app/dialogs/tokens-frame.tsx @@ -1,15 +1,22 @@ import { faQuestionCircle, Icon } from "@rivet-gg/icons"; -import { useQuery } from "@tanstack/react-query"; +import { useInfiniteQuery, useQuery } from "@tanstack/react-query"; import { useRouteContext } from "@tanstack/react-router"; +import { useEffect, useState } from "react"; +import { match } from "ts-pattern"; import { HelpDropdown } from "@/app/help-dropdown"; +import { PublishableTokenCodeGroup } from "@/app/publishable-token-code-group"; import { Button, + CodePreview, type DialogContentProps, DiscreteInput, Frame, + getConfig, Label, Skeleton, } from "@/components"; +import { RegionSelect } from "@/components/actors/region-select"; +import { cloudEnv } from "@/lib/env"; interface TokensFrameContentProps extends DialogContentProps {} @@ -20,7 +27,7 @@ export default function TokensFrameContent({ <> -
Namespace Tokens
+
App Tokens
- - +

Overview

+ - - +

Connect your RivetKit application to Rivet Cloud. Use @@ -197,22 +190,17 @@ export function RouteComponent() {

Connect Existing Project

-
- - - - +
-

Connect your RivetKit application to Rivet Cloud. Use your cloud of choice to run Rivet Actors. @@ -320,11 +308,7 @@ export function RouteComponent() {

-

Connect

-
- - - +

Overview

-

Connect your RivetKit application to Rivet Cloud. Use your cloud of choice to run Rivet Actors. @@ -367,7 +350,7 @@ function Providers() { return (

-
+

Providers

@@ -436,21 +419,23 @@ function Runners() { } function usePublishableToken() { - const cloudProvider = useCloudNamespaceDataProvider(); - const engineProvider = useEngineNamespaceDataProvider(); - const cloudData = useSuspenseQuery( - cloudProvider.publishableTokenQueryOptions(), - ); - const engineData = useSuspenseQuery( - engineProvider.engineAdminTokenQueryOptions(), - ); + if (__APP_TYPE__ === "cloud") { + const cloudProvider = useCloudNamespaceDataProvider(); + const cloudData = useSuspenseQuery( + cloudProvider.publishableTokenQueryOptions(), + ); + return cloudData.data; + } - return match(__APP_TYPE__) - .with("cloud", () => cloudData.data) - .with("engine", () => engineData.data) - .otherwise(() => { - throw new Error("Not in a valid context"); - }); + if (__APP_TYPE__ === "engine") { + const engineProvider = useEngineNamespaceDataProvider(); + const engineData = useSuspenseQuery( + engineProvider.engineAdminTokenQueryOptions(), + ); + return engineData.data; + } + + throw new Error("Not in a valid context"); } const useEndpoint = () => { @@ -472,90 +457,6 @@ function ConnectYourFrontend() { const dataProvider = useEngineCompatDataProvider(); const namespace = dataProvider.engineNamespace; - const { data: configs } = useInfiniteQuery({ - ...dataProvider.runnerConfigsQueryOptions(), - refetchInterval: 5000, - }); - - // Check if Vercel is connected - const hasVercel = hasProvider(configs, ["vercel", "next-js"]); - - const nextJsTab = ( - - - See Next.js Documentation{" "} - - - - } - > - - - ); - - const reactTab = ( - - - See React Documentation{" "} - - - - } - > - - - ); - - const javascriptTab = ( - - - See JavaScript Documentation{" "} - - - - } - > - - - ); - return (
@@ -565,69 +466,16 @@ function ConnectYourFrontend() { This token is safe to publish on your frontend.

- - {hasVercel - ? [nextJsTab, reactTab, javascriptTab] - : [javascriptTab, reactTab, nextJsTab]} - +
); } -const javascriptCode = ({ - token, - endpoint, - namespace, -}: { - token: string; - endpoint: string; - namespace: string; -}) => `import { createClient } from "rivetkit/client"; -import type { registry } from "./registry"; - -const client = createClient({ - endpoint: "${endpoint}", - namespace: "${namespace}", - token: "${token}", -});`; - -const reactCode = ({ - token, - endpoint, - namespace, -}: { - token: string; - endpoint: string; - namespace: string; -}) => `import { createRivetKit } from "@rivetkit/react"; -import type { registry } from "./registry"; - -export const { useActor } = createRivetKit({ - endpoint: "${endpoint}", - namespace: "${namespace}", - token: "${token}", -});`; - -const nextJsCode = ({ - token, - endpoint, - namespace, -}: { - token: string; - endpoint: string; - namespace: string; -}) => `"use client"; -import { createRivetKit } from "@rivetkit/next-js/client"; -import type { registry } from "@/rivet/registry"; - -export const { useActor } = createRivetKit({ - endpoint: "${engineEnv().VITE_APP_API_URL}", - namespace: "${namespace}", - token: "${token}", -}); -`; - function ProviderDropdown({ children }: { children: React.ReactNode }) { const navigate = Route.useNavigate(); return ( diff --git a/frontend/src/routes/_context/_cloud/orgs.$organization/projects.$project/ns.$namespace/tokens.tsx b/frontend/src/routes/_context/_cloud/orgs.$organization/projects.$project/ns.$namespace/tokens.tsx new file mode 100644 index 0000000000..2c199404c2 --- /dev/null +++ b/frontend/src/routes/_context/_cloud/orgs.$organization/projects.$project/ns.$namespace/tokens.tsx @@ -0,0 +1,546 @@ +import { faChevronRight, faCopy, faNodeJs, faPlus, faQuestionCircle, faTrash, Icon } from "@rivet-gg/icons"; +import { useInfiniteQuery, useMutation, useQuery } from "@tanstack/react-query"; +import { createFileRoute, useParams, useRouteContext } from "@tanstack/react-router"; +import { useEffect, useState } from "react"; +import { toast } from "sonner"; +import { match } from "ts-pattern"; +import { HelpDropdown } from "@/app/help-dropdown"; +import { PublishableTokenCodeGroup } from "@/app/publishable-token-code-group"; +import { useDialog } from "@/app/use-dialog"; +import { + Badge, + Button, + CodeFrame, + CodeGroup, + CodePreview, + DiscreteInput, + DocsSheet, + getConfig, + H1, + H3, + Label, + Skeleton, + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components"; +import { useEngineCompatDataProvider } from "@/components/actors"; +import { RegionSelect } from "@/components/actors/region-select"; +import { cloudEnv } from "@/lib/env"; +import { queryClient } from "@/queries/global"; + +export const Route = createFileRoute( + "/_context/_cloud/orgs/$organization/projects/$project/ns/$namespace/tokens", +)({ + component: RouteComponent, +}); + +function RouteComponent() { + return ( +
+
+
+

Tokens

+ + + +
+

+ These tokens are used to authenticate your app with Rivet. +

+
+
+
+ + + +
+
+ ); +} + +function PublishableToken() { + const dataProvider = useEngineCompatDataProvider(); + const { data: token, isLoading } = useQuery( + dataProvider.publishableTokenQueryOptions(), + ); + + const namespace = dataProvider.engineNamespace; + + const endpoint = match(__APP_TYPE__) + .with("cloud", () => cloudEnv().VITE_APP_API_URL) + .with("engine", () => getConfig().apiUrl) + .otherwise(() => { + throw new Error("Not in a valid context"); + }); + + return ( +
+
+

Client Token

+
+

+ Connect to your actors using the Rivet client token. This can be used either on your frontend or backend. +

+
+ {isLoading ? ( + + ) : ( + + )} + {token && ( + + )} +
+
+ ); +} + +function SecretToken() { + const dataProvider = useEngineCompatDataProvider(); + const { data: token, isLoading: isTokenLoading } = useQuery( + dataProvider.engineAdminTokenQueryOptions(), + ); + const { data: regions = [] } = useInfiniteQuery( + dataProvider.regionsQueryOptions(), + ); + const [selectedDatacenter, setSelectedDatacenter] = useState< + string | undefined + >(undefined); + + // Set default datacenter when regions are loaded + useEffect(() => { + if (regions.length > 0 && !selectedDatacenter) { + setSelectedDatacenter(regions[0].id); + } + }, [regions, selectedDatacenter]); + + const namespace = dataProvider.engineNamespace; + + const endpoint = match(__APP_TYPE__) + .with("cloud", () => { + const region = regions.find((r) => r.id === selectedDatacenter); + return region?.endpoint || cloudEnv().VITE_APP_API_URL; + }) + .with("engine", () => getConfig().apiUrl) + .otherwise(() => { + throw new Error("Not in a valid context"); + }); + + const codeSnippet = `import { registry } from "./registry"; + +// Automatically reads token from env +registry.start();`; + + return ( +
+
+

Runner Token

+
+

+ Used by runners (servers that run your actors) to authenticate + with Rivet. Serverless providers do not need to use this token. +

+
+
+ + +
+
+ +
+ + + + + + + + {isTokenLoading ? ( + + ) : ( + + )} +
+
+ +
+
+ + {[ + codeSnippet} + footer={ + + + See JavaScript Documentation{" "} + + + + } + > + + + ]} + +
+
+ ); +} + +function CloudApiTokens() { + const { dataProvider } = useRouteContext({ + from: "/_context/_cloud/orgs/$organization/projects/$project", + }); + const params = useParams({ strict: false }); + const organization = params.organization; + const project = params.project; + const namespace = params.namespace; + + const { data, isLoading } = useQuery(dataProvider.apiTokensQueryOptions()); + + const { open: openCreateApiToken, dialog: createApiTokenDialog } = + useDialog.CreateApiToken({}); + + const cloudApiUrl = cloudEnv().VITE_APP_CLOUD_API_URL; + + return ( +
+
+
+

Cloud API Tokens

+ Beta +
+ +
+

+ Cloud API tokens provide programmatic access to the Rivet Cloud API. Keep + them secure and never share them publicly. +

+
+ {isLoading ? ( +
+ + + +
+ ) : ( + + + + Name + Token + Created + Expires + + + + + {data?.apiTokens.length === 0 ? ( + + + No Cloud API tokens yet. Create one to get started. + + + ) : ( + data?.apiTokens.map((apiToken) => ( + + )) + )} + +
+ )} +
+
+ + `const response = await fetch("${cloudApiUrl}/projects/${project}/namespaces?org=${organization}", { + method: "POST", + headers: { + "Authorization": "Bearer \${YOUR_CLOUD_API_TOKEN}", + "Content-Type": "application/json" + }, + body: JSON.stringify({ + displayName: "my-namespace" + }) +}); + +const data = await response.json(); +console.log(data.namespace);`} + > + + + `const response = await fetch("${cloudApiUrl}/projects/${project}/namespaces?org=${organization}&limit=10", { + method: "GET", + headers: { + "Authorization": "Bearer \${YOUR_CLOUD_API_TOKEN}" + } +}); + +const data = await response.json(); +console.log(data.namespaces);`} + > + + + `const response = await fetch("${cloudApiUrl}/projects/${project}/namespaces/${namespace}?org=${organization}", { + method: "GET", + headers: { + "Authorization": "Bearer \${YOUR_CLOUD_API_TOKEN}" + } +}); + +const data = await response.json(); +console.log(data.namespace);`} + > + + + `const response = await fetch("${cloudApiUrl}/projects/${project}/namespaces/${namespace}/tokens/secret?org=${organization}", { + method: "POST", + headers: { + "Authorization": "Bearer \${YOUR_CLOUD_API_TOKEN}" + } +}); + +const data = await response.json(); +console.log(data.token);`} + > + + + `const response = await fetch("${cloudApiUrl}/projects/${project}/namespaces/${namespace}/tokens/publishable?org=${organization}", { + method: "POST", + headers: { + "Authorization": "Bearer \${YOUR_CLOUD_API_TOKEN}" + } +}); + +const data = await response.json(); +console.log(data.token);`} + > + + + +
+ {createApiTokenDialog} +
+ ); +} + +interface ApiTokenRowProps { + apiToken: { + id: string; + name: string; + createdAt: string; + expiresAt?: string; + revoked: boolean; + lastFourChars: string; + }; + dataProvider: ReturnType< + typeof useRouteContext<"/_context/_cloud/orgs/$organization/projects/$project"> + >["dataProvider"]; +} + +function ApiTokenRow({ apiToken, dataProvider }: ApiTokenRowProps) { + const { mutate: revoke, isPending } = useMutation( + dataProvider.revokeApiTokenMutationOptions({ + onSuccess: async () => { + await queryClient.invalidateQueries( + dataProvider.apiTokensQueryOptions(), + ); + }, + }), + ); + + const createdDate = new Date(apiToken.createdAt).toLocaleDateString(); + const expiresDate = apiToken.expiresAt + ? new Date(apiToken.expiresAt).toLocaleDateString() + : "Never"; + + return ( + + {apiToken.name} + + + cloud_api_...{apiToken.lastFourChars} + + + {createdDate} + {expiresDate} + + {!apiToken.revoked && ( + + )} + {apiToken.revoked && ( + Revoked + )} + + + ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3c099fdfa..2dae23c7cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1637,8 +1637,8 @@ importers: specifier: ^1.2.3 version: 1.2.3(@types/react-dom@19.2.2(@types/react@19.2.2))(@types/react@19.2.2)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@rivet-gg/cloud': - specifier: https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@1fcfb72 - version: https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@1fcfb72 + specifier: https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@11dea2c + version: https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@11dea2c '@rivet-gg/icons': specifier: workspace:* version: link:packages/icons @@ -6417,8 +6417,8 @@ packages: '@rivet-gg/api@25.5.3': resolution: {integrity: sha512-pj8xYQ+I/aQDbThmicPxvR+TWAzGoLSE53mbJi4QZHF8VH2oMvU7CMWqy7OTFH30DIRyVzsnHHRJZKGwtmQL3g==} - '@rivet-gg/cloud@https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@1fcfb72': - resolution: {tarball: https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@1fcfb72} + '@rivet-gg/cloud@https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@11dea2c': + resolution: {tarball: https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@11dea2c} version: 0.0.0 '@rivet-gg/cloud@https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@bf2ebb2': @@ -18266,7 +18266,7 @@ snapshots: transitivePeerDependencies: - encoding - '@rivet-gg/cloud@https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@1fcfb72': + '@rivet-gg/cloud@https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@11dea2c': dependencies: cross-fetch: 4.1.0 form-data: 4.0.5