Skip to content

Commit 17c313d

Browse files
committed
feat: cloud acl
1 parent 56b6dd4 commit 17c313d

File tree

12 files changed

+204
-149
lines changed

12 files changed

+204
-149
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: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import {
1616
RECORDS_PER_PAGE,
1717
} from "./default-data-provider";
1818

19+
const mightRequireAuth = __APP_TYPE__ === "engine";
20+
1921
export type CreateNamespace = {
2022
displayName: string;
21-
name?: string;
2223
};
2324

2425
export type Namespace = {
@@ -30,7 +31,7 @@ export type Namespace = {
3031

3132
export function createClient(
3233
baseUrl = engineEnv().VITE_APP_API_URL,
33-
opts: { token: (() => string) | string },
34+
opts: { token: (() => string) | string | (() => Promise<string>) },
3435
) {
3536
return new RivetClient({
3637
baseUrl: () => baseUrl,
@@ -87,7 +88,7 @@ export const createGlobalContext = (opts: {
8788
mutationFn: async (data: CreateNamespace) => {
8889
const response = await client.namespaces.create({
8990
displayName: data.displayName,
90-
name: data.name || convertStringToId(data.displayName),
91+
name: convertStringToId(data.displayName),
9192
});
9293

9394
return {
@@ -132,7 +133,7 @@ export const createNamespaceContext = ({
132133
retry: shouldRetryAllExpect403,
133134
throwOnError: noThrow,
134135
meta: {
135-
mightRequireAuth: true,
136+
mightRequireAuth,
136137
},
137138
});
138139
},
@@ -157,7 +158,7 @@ export const createNamespaceContext = ({
157158
retry: shouldRetryAllExpect403,
158159
throwOnError: noThrow,
159160
meta: {
160-
mightRequireAuth: true,
161+
mightRequireAuth,
161162
},
162163
});
163164
},
@@ -186,7 +187,7 @@ export const createNamespaceContext = ({
186187
retry: shouldRetryAllExpect403,
187188
throwOnError: noThrow,
188189
meta: {
189-
mightRequireAuth: true,
190+
mightRequireAuth,
190191
},
191192
});
192193
},
@@ -213,7 +214,7 @@ export const createNamespaceContext = ({
213214
retry: shouldRetryAllExpect403,
214215
throwOnError: noThrow,
215216
meta: {
216-
mightRequireAuth: true,
217+
mightRequireAuth,
217218
},
218219
});
219220
},
@@ -288,7 +289,7 @@ export const createNamespaceContext = ({
288289
retry: shouldRetryAllExpect403,
289290
throwOnError: noThrow,
290291
meta: {
291-
mightRequireAuth: true,
292+
mightRequireAuth,
292293
},
293294
});
294295
},
@@ -329,7 +330,7 @@ export const createNamespaceContext = ({
329330
retry: shouldRetryAllExpect403,
330331
throwOnError: noThrow,
331332
meta: {
332-
mightRequireAuth: true,
333+
mightRequireAuth,
333334
},
334335
});
335336
},
@@ -353,7 +354,7 @@ export const createNamespaceContext = ({
353354
throwOnError: noThrow,
354355
retry: shouldRetryAllExpect403,
355356
meta: {
356-
mightRequireAuth: true,
357+
mightRequireAuth,
357358
},
358359
};
359360
},
@@ -363,7 +364,7 @@ export const createNamespaceContext = ({
363364
throwOnError: noThrow,
364365
retry: shouldRetryAllExpect403,
365366
meta: {
366-
mightRequireAuth: true,
367+
mightRequireAuth,
367368
},
368369
mutationFn: async () => {
369370
await client.actorsDelete(actorId);
@@ -374,14 +375,14 @@ export const createNamespaceContext = ({
374375

375376
return {
376377
...dataProvider,
377-
runnersQueryOptions(opts: { namespace: string }) {
378+
runnersQueryOptions() {
378379
return infiniteQueryOptions({
379-
queryKey: [opts.namespace, "runners"],
380+
queryKey: [{ namespace }, "runners"],
380381
initialPageParam: undefined as string | undefined,
381382
queryFn: async ({ pageParam, signal: abortSignal }) => {
382383
const data = await client.runners.list(
383384
{
384-
namespace: opts.namespace,
385+
namespace,
385386
cursor: pageParam ?? undefined,
386387
limit: RECORDS_PER_PAGE,
387388
},
@@ -398,7 +399,7 @@ export const createNamespaceContext = ({
398399
select: (data) => data.pages.flatMap((page) => page.runners),
399400
retry: shouldRetryAllExpect403,
400401
meta: {
401-
mightRequireAuth: true,
402+
mightRequireAuth,
402403
},
403404
});
404405
},
@@ -429,7 +430,7 @@ export const createNamespaceContext = ({
429430
retry: shouldRetryAllExpect403,
430431
throwOnError: noThrow,
431432
meta: {
432-
mightRequireAuth: true,
433+
mightRequireAuth,
433434
},
434435
});
435436
},
@@ -456,7 +457,7 @@ export const createNamespaceContext = ({
456457
throwOnError: noThrow,
457458
retry: shouldRetryAllExpect403,
458459
meta: {
459-
mightRequireAuth: true,
460+
mightRequireAuth,
460461
},
461462
});
462463
},
@@ -481,7 +482,7 @@ export const createNamespaceContext = ({
481482
},
482483
retry: shouldRetryAllExpect403,
483484
meta: {
484-
mightRequireAuth: true,
485+
mightRequireAuth,
485486
},
486487
});
487488
},
@@ -506,6 +507,10 @@ export const createNamespaceContext = ({
506507
});
507508
return response;
508509
},
510+
retry: shouldRetryAllExpect403,
511+
meta: {
512+
mightRequireAuth,
513+
},
509514
};
510515
},
511516
runnerConfigsQueryOptions() {
@@ -538,6 +543,12 @@ export const createNamespaceContext = ({
538543
}
539544
return lastPage.pagination.cursor;
540545
},
546+
547+
retryDelay: 50_000,
548+
retry: shouldRetryAllExpect403,
549+
meta: {
550+
mightRequireAuth,
551+
},
541552
});
542553
},
543554
};

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)