Skip to content

Commit 0d5ffc4

Browse files
committed
feat: cloud acl
1 parent aadd55a commit 0d5ffc4

File tree

12 files changed

+205
-150
lines changed

12 files changed

+205
-150
lines changed

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"@radix-ui/react-toggle-group": "^1.1.11",
5959
"@radix-ui/react-tooltip": "^1.2.8",
6060
"@radix-ui/react-visually-hidden": "^1.2.3",
61-
"@rivet-gg/cloud": "file:vendor/rivet-cloud.tgz",
61+
"@rivet-gg/cloud": "https://pkg.pr.new/rivet-dev/cloud/@rivet-gg/cloud@7090780",
6262
"@rivet-gg/icons": "workspace:*",
6363
"rivetkit": "*",
6464
"@rivetkit/engine-api-full": "workspace:*",

frontend/src/app/data-providers/cloud-data-provider.tsx

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { type Rivet, RivetClient } from "@rivet-gg/cloud";
33
import { type FetchFunction, fetcher } from "@rivetkit/engine-api-full/core";
44
import { infiniteQueryOptions, queryOptions } from "@tanstack/react-query";
55
import { cloudEnv } from "@/lib/env";
6+
import { queryClient } from "@/queries/global";
67
import { RECORDS_PER_PAGE } from "./default-data-provider";
78
import {
89
type CreateNamespace,
@@ -209,8 +210,7 @@ export const createOrganizationContext = ({
209210
}) => {
210211
const response = await client.projects.create({
211212
displayName: data.displayName,
212-
name: data.nameId,
213-
organizationId: organization,
213+
org: organization,
214214
});
215215

216216
return response;
@@ -241,7 +241,6 @@ export const createProjectContext = ({
241241
mutationKey: ["namespaces"],
242242
mutationFn: async (data: CreateNamespace) => {
243243
const response = await client.namespaces.create(project, {
244-
name: data.name,
245244
displayName: data.displayName,
246245
org: organization,
247246
});
@@ -304,20 +303,37 @@ export const createProjectContext = ({
304303
},
305304
};
306305
},
306+
accessTokenQueryOptions({ namespace }: { namespace: string }) {
307+
return queryOptions({
308+
staleTime: 15 * 60 * 1000, // 15 minutes
309+
gcTime: 15 * 60 * 1000, // 15 minutes
310+
queryKey: [
311+
{ organization, project, namespace },
312+
"access-token",
313+
],
314+
queryFn: async ({ signal: abortSignal }) => {
315+
const response = await client.namespaces.createAccessToken(
316+
project,
317+
namespace,
318+
{ org: organization },
319+
{ abortSignal },
320+
);
321+
return response;
322+
},
323+
});
324+
},
307325
};
308326
};
309327

310328
export const createNamespaceContext = ({
311329
namespace,
312330
engineNamespaceName,
313331
engineNamespaceId,
314-
engineToken,
315332
...parent
316333
}: {
317334
namespace: string;
318335
engineNamespaceName: string;
319336
engineNamespaceId: string;
320-
engineToken?: (() => string) | string;
321337
} & ReturnType<typeof createProjectContext> &
322338
ReturnType<typeof createOrganizationContext> &
323339
ReturnType<typeof createGlobalContext>) => {
@@ -327,7 +343,13 @@ export const createNamespaceContext = ({
327343
namespace: engineNamespaceName,
328344
namespaceId: engineNamespaceId,
329345
client: createEngineClient(cloudEnv().VITE_APP_CLOUD_ENGINE_URL, {
330-
token: engineToken,
346+
token: async () => {
347+
const response = await queryClient.fetchQuery(
348+
parent.accessTokenQueryOptions({ namespace }),
349+
);
350+
351+
return response.token;
352+
},
331353
}),
332354
}),
333355
namespaceQueryOptions() {

frontend/src/app/data-providers/engine-data-provider.tsx

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ import {
1717
} from "./default-data-provider";
1818
import { getConfig } from "@/components/lib/config";
1919

20+
const mightRequireAuth = __APP_TYPE__ === "engine";
21+
2022
export type CreateNamespace = {
2123
displayName: string;
22-
name?: string;
2324
};
2425

2526
export type Namespace = {
@@ -30,8 +31,8 @@ export type Namespace = {
3031
};
3132

3233
export function createClient(
33-
baseUrl = getConfig().apiUrl,
34-
opts: { token: (() => string) | string },
34+
baseUrl = engineEnv().VITE_APP_API_URL,
35+
opts: { token: (() => string) | string | (() => Promise<string>) },
3536
) {
3637
return new RivetClient({
3738
baseUrl: () => baseUrl,
@@ -88,7 +89,7 @@ export const createGlobalContext = (opts: {
8889
mutationFn: async (data: CreateNamespace) => {
8990
const response = await client.namespaces.create({
9091
displayName: data.displayName,
91-
name: data.name || convertStringToId(data.displayName),
92+
name: convertStringToId(data.displayName),
9293
});
9394

9495
return {
@@ -133,7 +134,7 @@ export const createNamespaceContext = ({
133134
retry: shouldRetryAllExpect403,
134135
throwOnError: noThrow,
135136
meta: {
136-
mightRequireAuth: true,
137+
mightRequireAuth,
137138
},
138139
});
139140
},
@@ -158,7 +159,7 @@ export const createNamespaceContext = ({
158159
retry: shouldRetryAllExpect403,
159160
throwOnError: noThrow,
160161
meta: {
161-
mightRequireAuth: true,
162+
mightRequireAuth,
162163
},
163164
});
164165
},
@@ -187,7 +188,7 @@ export const createNamespaceContext = ({
187188
retry: shouldRetryAllExpect403,
188189
throwOnError: noThrow,
189190
meta: {
190-
mightRequireAuth: true,
191+
mightRequireAuth,
191192
},
192193
});
193194
},
@@ -214,7 +215,7 @@ export const createNamespaceContext = ({
214215
retry: shouldRetryAllExpect403,
215216
throwOnError: noThrow,
216217
meta: {
217-
mightRequireAuth: true,
218+
mightRequireAuth,
218219
},
219220
});
220221
},
@@ -289,7 +290,7 @@ export const createNamespaceContext = ({
289290
retry: shouldRetryAllExpect403,
290291
throwOnError: noThrow,
291292
meta: {
292-
mightRequireAuth: true,
293+
mightRequireAuth,
293294
},
294295
});
295296
},
@@ -330,7 +331,7 @@ export const createNamespaceContext = ({
330331
retry: shouldRetryAllExpect403,
331332
throwOnError: noThrow,
332333
meta: {
333-
mightRequireAuth: true,
334+
mightRequireAuth,
334335
},
335336
});
336337
},
@@ -354,7 +355,7 @@ export const createNamespaceContext = ({
354355
throwOnError: noThrow,
355356
retry: shouldRetryAllExpect403,
356357
meta: {
357-
mightRequireAuth: true,
358+
mightRequireAuth,
358359
},
359360
};
360361
},
@@ -364,7 +365,7 @@ export const createNamespaceContext = ({
364365
throwOnError: noThrow,
365366
retry: shouldRetryAllExpect403,
366367
meta: {
367-
mightRequireAuth: true,
368+
mightRequireAuth,
368369
},
369370
mutationFn: async () => {
370371
await client.actorsDelete(actorId);
@@ -375,14 +376,14 @@ export const createNamespaceContext = ({
375376

376377
return {
377378
...dataProvider,
378-
runnersQueryOptions(opts: { namespace: string }) {
379+
runnersQueryOptions() {
379380
return infiniteQueryOptions({
380-
queryKey: [opts.namespace, "runners"],
381+
queryKey: [{ namespace }, "runners"],
381382
initialPageParam: undefined as string | undefined,
382383
queryFn: async ({ pageParam, signal: abortSignal }) => {
383384
const data = await client.runners.list(
384385
{
385-
namespace: opts.namespace,
386+
namespace,
386387
cursor: pageParam ?? undefined,
387388
limit: RECORDS_PER_PAGE,
388389
},
@@ -399,7 +400,7 @@ export const createNamespaceContext = ({
399400
select: (data) => data.pages.flatMap((page) => page.runners),
400401
retry: shouldRetryAllExpect403,
401402
meta: {
402-
mightRequireAuth: true,
403+
mightRequireAuth,
403404
},
404405
});
405406
},
@@ -430,7 +431,7 @@ export const createNamespaceContext = ({
430431
retry: shouldRetryAllExpect403,
431432
throwOnError: noThrow,
432433
meta: {
433-
mightRequireAuth: true,
434+
mightRequireAuth,
434435
},
435436
});
436437
},
@@ -457,7 +458,7 @@ export const createNamespaceContext = ({
457458
throwOnError: noThrow,
458459
retry: shouldRetryAllExpect403,
459460
meta: {
460-
mightRequireAuth: true,
461+
mightRequireAuth,
461462
},
462463
});
463464
},
@@ -482,7 +483,7 @@ export const createNamespaceContext = ({
482483
},
483484
retry: shouldRetryAllExpect403,
484485
meta: {
485-
mightRequireAuth: true,
486+
mightRequireAuth,
486487
},
487488
});
488489
},
@@ -507,6 +508,10 @@ export const createNamespaceContext = ({
507508
});
508509
return response;
509510
},
511+
retry: shouldRetryAllExpect403,
512+
meta: {
513+
mightRequireAuth,
514+
},
510515
};
511516
},
512517
runnerConfigsQueryOptions() {
@@ -539,6 +544,12 @@ export const createNamespaceContext = ({
539544
}
540545
return lastPage.pagination.cursor;
541546
},
547+
548+
retryDelay: 50_000,
549+
retry: shouldRetryAllExpect403,
550+
meta: {
551+
mightRequireAuth,
552+
},
542553
});
543554
},
544555
};

frontend/src/app/forms/connect-vercel-form.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ import {
1616
Input,
1717
Label,
1818
ScrollArea,
19+
Select,
20+
SelectContent,
21+
SelectItem,
22+
SelectTrigger,
23+
SelectValue,
1924
} from "@/components";
2025
import { useCloudDataProvider } from "@/components/actors";
2126

@@ -26,6 +31,7 @@ export const formSchema = z.object({
2631
.refine((value) => value.trim() !== "" && value.trim() === value, {
2732
message: "Name cannot be empty or contain whitespaces",
2833
}),
34+
plan: z.string(),
2935
endpoint: z.string().url(),
3036
});
3137

@@ -61,6 +67,42 @@ export const Name = ({ className }: { className?: string }) => {
6167
);
6268
};
6369

70+
export const Plan = ({ className }: { className?: string }) => {
71+
const { control } = useFormContext<FormValues>();
72+
return (
73+
<FormField
74+
control={control}
75+
name="plan"
76+
render={({ field }) => (
77+
<FormItem className={className}>
78+
<FormLabel className="col-span-1">Plan</FormLabel>
79+
<FormControl className="row-start-2">
80+
<Select
81+
onValueChange={field.onChange}
82+
value={field.value}
83+
>
84+
<SelectTrigger
85+
variant="ghost"
86+
className="h-full pr-2 rounded-none"
87+
>
88+
<SelectValue placeholder="Select table or view..." />
89+
</SelectTrigger>
90+
<SelectContent>
91+
<SelectItem value="hobby">Hobby</SelectItem>
92+
<SelectItem value="pro">Pro</SelectItem>
93+
<SelectItem value="enterprise">
94+
Enterprise
95+
</SelectItem>
96+
</SelectContent>
97+
</Select>
98+
</FormControl>
99+
<FormMessage className="col-span-1" />
100+
</FormItem>
101+
)}
102+
/>
103+
);
104+
};
105+
64106
export const Endpoint = ({ className }: { className?: string }) => {
65107
const { control } = useFormContext<FormValues>();
66108
return (

frontend/src/app/layout.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,12 +397,12 @@ const Subnav = () => {
397397
<div className="flex gap-1.5 flex-col">
398398
{__APP_TYPE__ === "engine" ? (
399399
<HeaderLink
400-
to="/ns/$namespace/runners"
400+
to="/ns/$namespace/connect"
401401
className="font-normal"
402402
params={nsMatch}
403-
icon={faServer}
403+
icon={faBolt}
404404
>
405-
Runners
405+
Connect
406406
</HeaderLink>
407407
) : null}
408408
<div className="w-full">

frontend/src/queries/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import type { Query } from "@tanstack/react-query";
33
export const shouldRetryAllExpect403 = (failureCount: number, error: Error) => {
44
if (error && "statusCode" in error) {
55
if (error.statusCode === 403) {
6-
// Don't retry on auth errors
7-
return false;
6+
// Don't retry on auth errors, when app is not engine
7+
return __APP_TYPE__ !== "engine";
88
}
99
}
1010

0 commit comments

Comments
 (0)