I'm using next v14.1.0 and I'm trying to run a server action as follows
'use server';
import { Updateable } from 'kysely';
import { db, OrganizationRecord } from '@project/core/db/db';
import { setTimeout } from 'timers/promises';
export type UpdatableOrganization = Updateable<OrganizationRecord>;
export async function upsertOrganization(organization: UpdatableOrganization) {
await setTimeout(1000);
db.insertInto('organizations').values({
name: 'asdf',
description: 'asdf',
createdAt: new Date(),
updatedAt: new Date(),
});
}
Somehow the first await
doesn't give me any issues, but the moment I try to execute the second statement, event though I'm not awaiting it, I get an error SyntaxError: await is only valid in async functions and the top level bodies of modules
. I observed the same error with a number of selected functions. This one comes from kysely
, but the same thing happens for instance when I call getServerSession()
from next-auth
.
Here's how I call the upsertOrganization
'use client';
import * as React from 'react';
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from '@/registry/new-york/ui/dialog';
import { Input } from '@/registry/new-york/ui/input';
import { Button } from '@/registry/new-york/ui/button';
import { EditableOrganization } from '@/app/home/components/edit-organization-dialog/editable-organization';
import {
UpdatableOrganization,
upsertOrganization,
} from '@/app/home/components/edit-organization-dialog/edit-organization';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from '@/registry/new-york/ui/form';
import {
organizationFormSchema,
OrganizationFormSchema,
} from '@/app/home/components/edit-organization-dialog/edit-organiation-validation';
export default function EditOrganizationDialog({
visible,
setVisible,
existingOrganization,
}: {
visible: boolean;
existingOrganization?: UpdatableOrganization;
setVisible: (props: EditableOrganization) => void;
}) {
const [processing, setProcessing] = useState(false);
const form = useForm<OrganizationFormSchema>({
resolver: zodResolver(organizationFormSchema),
mode: 'onChange',
defaultValues: {
name: '',
description: '',
},
values: {
name: existingOrganization?.name ?? '',
description: existingOrganization?.description ?? '',
},
});
const insertOrUpdateOrganization = async (data: OrganizationFormSchema) => {
setProcessing(true);
try {
await upsertOrganization({
...data,
id: existingOrganization?.id,
});
setVisible({
visible: false,
});
} catch (err) {
console.error(err);
} finally {
setProcessing(false);
}
};
return (
<Dialog
open={visible}
onOpenChange={(visible: boolean) =>
setVisible({ visible, organization: existingOrganization })
}
>
<DialogContent>
<DialogHeader>
<DialogTitle>
{existingOrganization ? 'Edit' : 'Create'} Organization
</DialogTitle>
<DialogDescription>
{existingOrganization
? `Edit the organization "${existingOrganization.name}"`
: 'Add a new organization to manage your team.'}
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(insertOrUpdateOrganization)}>
<div className="space-y-4 py-2 pb-4">
<div className="space-y-2">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Organization Name</FormLabel>
<FormControl>
<Input
placeholder="Organization Name"
{...field}
disabled={processing}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<div className="space-y-2">
<FormField
control={form.control}
name="description"
render={({ field }) => (
<FormItem>
<FormLabel>Organization Description</FormLabel>
<FormControl>
<Input
placeholder="Organization description"
{...field}
disabled={processing}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
<DialogFooter>
<Button
disabled={processing}
variant="outline"
onClick={() =>
setVisible({
visible: false,
organization: existingOrganization,
})
}
>
Cancel
</Button>
<Button type="submit" disabled={processing}>
{existingOrganization ? 'Update' : 'Create'}
</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
}
Any idea what is going on here?