"await is only valid in async functions" error when calling kysely from server actions

48 Views Asked by At

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?

0

There are 0 best solutions below