generateCloudflareWorkerWrapper function

String generateCloudflareWorkerWrapper(
  1. String compiledPath,
  2. Iterable<String> durableObjectClasses, {
  3. Map<String, int> containerPorts = const <String, int>{},
  4. String? ssrEntry,
})

Generates the JavaScript wrapper that exports Cloudflare bindings.

compiledPath is the path to the Dart-compiled Worker JavaScript. The generated wrapper imports its basename, exposes each class in durableObjectClasses as a Durable Object class, and exposes container classes from containerPorts using their configured TCP port. The result is intended to be written as the Wrangler main file alongside the compiled JavaScript.

When ssrEntry is supplied, it must refer to a bundled ES module whose default export exposes a Cloudflare Fetch-compatible fetch method. The wrapper dispatches /__ssr requests to that module and leaves all other requests to the Routed Worker.

final wrapper = generateCloudflareWorkerWrapper(
  '.dart_tool/routed/deploy/cloudflare/worker.dart.js',
  const ['Counter'],
  containerPorts: const {'ApiContainer': 8080},
);

Implementation

String generateCloudflareWorkerWrapper(
  String compiledPath,
  Iterable<String> durableObjectClasses, {
  Map<String, int> containerPorts = const <String, int>{},
  String? ssrEntry,
}) {
  final relative = p.basename(compiledPath);
  final exports = durableObjectClasses
      .map((className) {
        // Generated JavaScript is intentionally emitted without a leading
        // newline so the wrapper remains stable for deployment tooling.
        // ignore: leading_newlines_in_multiline_strings
        return '''export class $className {
  constructor(state, env) {
    const factory = __routedDurableObjects['$className'];
    if (typeof factory !== 'function') {
      throw new Error('No Routed Durable Object factory registered for $className.');
    }
    this.delegate = factory(state, env);
  }

  fetch(request) {
    return this.delegate.fetch(request);
  }

  alarm() {
    return this.delegate.alarm();
  }

  webSocketMessage(webSocket, message) {
    return this.delegate.webSocketMessage(webSocket, message);
  }

  webSocketClose(webSocket, code, reason, wasClean) {
    return this.delegate.webSocketClose(webSocket, code, reason, wasClean);
  }

  webSocketError(webSocket, error) {
    return this.delegate.webSocketError(webSocket, error);
  }
}''';
      })
      .join('\n\n');
  final containerExports = containerPorts.entries
      .map((entry) {
        // Generated JavaScript is intentionally emitted without a leading
        // newline so the wrapper remains stable for deployment tooling.
        // ignore: leading_newlines_in_multiline_strings
        return '''export class ${entry.key} {
  constructor(state, env) {
    if (!state.container) {
      throw new Error('Cloudflare Container state is unavailable for ${entry.key}.');
    }
    this.container = state.container;
    this.container.start();
  }

  fetch(request) {
    return this.container.getTcpPort(${entry.value}).fetch(request);
  }
}''';
      })
      .join('\n\n');
  final sections = [
    if (exports.isNotEmpty) exports,
    if (containerExports.isNotEmpty) containerExports,
  ].join('\n\n');
  final ssrImport = ssrEntry == null
      ? ''
      : "import frontendSsr from './$ssrEntry';";
  final ssrDispatch = ssrEntry == null
      ? ''
      : '''
    const pathname = new URL(request.url).pathname;
    if (pathname === '/__ssr') {
      return await frontendSsr.fetch(request, env, ctx);
    }
    if (pathname !== '/' && pathname.lastIndexOf('.') > pathname.lastIndexOf('/')) {
      const asset = await env.ASSETS.fetch(request);
      if (asset.status !== 404) return asset;
    }
''';
  return '''
import './$relative';
$ssrImport

const __routedDurableObjects =
    globalThis.__routed_durable_objects__ ?? {};

$sections

export default {
  async fetch(request, env, ctx) {
$ssrDispatch
    return await globalThis.__routed_fetch__(request, ctx, env);
  },
};
''';
}