deployFunction method

Future<void> deployFunction({
  1. required String projectRef,
  2. required String accessToken,
  3. required String slug,
  4. required String entrypoint,
  5. required Map<String, String> files,
  6. bool verifyJwt = false,
})

Deploys (creates or updates) an Edge Function.

Maps to POST /v1/projects/{ref}/functions/deploy?slug=<slug>. The body is a multipart/form-data request containing:

  • a metadata text part with entrypoint_path + name (+ optional verify_jwt, defaulting to false — the relay's HS256-only check is replaced by in-function JWKS verification via _shared/jwt.ts)
  • one file part per source file, using the relative path as the filename so the Supabase runtime preserves the directory layout

files maps relative path → file contents. entrypoint must be one of the keys in files (e.g. index.ts). The function endpoint is idempotent: if a function with the same slug exists it is updated, otherwise a new one is created.

Implementation

Future<void> deployFunction({
  required String projectRef,
  required String accessToken,
  required String slug,
  required String entrypoint,
  required Map<String, String> files,
  bool verifyJwt = false,
}) async {
  if (!files.containsKey(entrypoint)) {
    throw ProvisioningException(
      'Function $slug is missing its entrypoint $entrypoint in the '
      'bundled source.',
    );
  }

  final url = '$_baseUrl/v1/projects/$projectRef/functions/deploy?slug=$slug';

  final metadata = {
    'entrypoint_path': entrypoint,
    'name': slug,
    'verify_jwt': verifyJwt,
  };

  final formData = FormData();
  formData.fields.add(MapEntry('metadata', jsonEncode(metadata)));
  for (final entry in files.entries) {
    formData.files.add(
      MapEntry(
        'file',
        MultipartFile.fromString(entry.value, filename: entry.key),
      ),
    );
  }

  final Response<dynamic> response;
  try {
    response = await _dio.post<dynamic>(
      url,
      data: formData,
      options: Options(
        headers: _authHeaders(accessToken),
        sendTimeout: _timeout,
        receiveTimeout: _timeout,
        validateStatus: (_) => true,
      ),
    );
  } on DioException catch (e) {
    throw ProvisioningException(
      _dioMessage(e, 'deploying Edge Function "$slug"'),
    );
  }

  final status = response.statusCode ?? 0;
  if (status >= 200 && status < 300) {
    dev.log(
      'Deployed function $slug to project $projectRef (HTTP $status).',
      name: 'SupabaseProvisioner',
    );
    return;
  }
  throw ProvisioningException(_mapStatus(status, projectRef, response.data));
}