run function

void run(
  1. List<String> args, {
  2. List<DartDeskPlugin> plugins = const [],
})

This is the starting point of your Serverpod server. In most cases, you will only need to make additions to this file if you add future calls, routes, or extensions that require setup at startup.

Implementation

void run(List<String> args, {List<DartDeskPlugin> plugins = const []}) async {
  final registry = DartDeskRegistry();

  // Load plugins
  for (final plugin in plugins) {
    plugin.register(registry);
  }

  // Make registry available to session extensions.
  DartDeskSession.setRegistry(registry);

  // Initialize Serverpod and connect it with your generated code.
  final pod = Serverpod(
    args,
    Protocol(),
    Endpoints(),
  );

  // Initialize email service from SMTP passwords.
  _emailService = _initEmailService(pod);

  // Initialize CRDT service with node ID from passwords.yaml
  final nodeId = pod.getPassword('crdtNodeId') ?? 'postgres-main';
  registry.documentCrdtService = DocumentCrdtService(nodeId);

  // Setup a default page at the web root.
  pod.webServer.addRoute(RouteRoot(), '/');
  pod.webServer.addRoute(RouteRoot(), '/index.html');

  // Serve uploaded files from storage/public directory
  pod.webServer.addRoute(
    StaticRoute.directory(Directory('storage/public')),
    '/files/*',
  );

  // Serve all files in the /static directory.
  pod.webServer.addRoute(
    StaticRoute.directory(Directory('static')),
    '/*',
  );

  pod.initializeAuthServices(
    tokenManagerBuilders: [
      JwtConfigFromPasswords(),
    ],
    identityProviderBuilders: [
      GoogleIdpConfig(
        clientSecret: GoogleClientSecret.fromJsonString(
          pod.getPassword('googleClientSecret')!,
        ),
      ),
      EmailIdpConfigFromPasswords(
        sendRegistrationVerificationCode: _sendRegistrationCode,
        sendPasswordResetVerificationCode: _sendPasswordResetCode,
      ),
    ],
  );

  // Override the authentication handler to chain JWT auth + API key auth.
  // initializeAuthServices sets the default JWT handler; we wrap it to also
  // support project API keys passed as "jwtToken:apiKey" compound tokens.
  final cloudAdminKey = pod.getPassword('cloudAdminKey');
  final defaultHandler = pod.authenticationHandler;
  pod.authenticationHandler = (session, token) async {
    // Cloud admin: a single privileged key stored in passwords.yaml / env.
    if (cloudAdminKey != null &&
        cloudAdminKey.isNotEmpty &&
        token == cloudAdminKey) {
      return AuthenticationInfo(
        'cloud-admin',
        {
          Scope('admin'),
          Scope('project.read'),
          Scope('project.write'),
        },
        authId: 'cloud-admin',
      );
    }

    final parsed = CompoundTokenParser.parse(token);
    final authToken = parsed.jwtToken;
    final apiKey = parsed.apiKey;

    final scopes = <Scope>{};
    String? userIdentifier;
    String? authId;

    if (authToken != null && authToken.isNotEmpty && authToken != 'null') {
      try {
        final authInfo = await defaultHandler?.call(session, authToken);
        if (authInfo != null) {
          userIdentifier = authInfo.userIdentifier;
          authId = authInfo.authId;
          scopes.addAll(authInfo.scopes);
          // JWT tokens may carry no scopes; ensure authenticated users are
          // never rejected solely because the scope set is empty.
          if (authInfo.scopes.isEmpty) {
            scopes.add(Scope('user'));
          }
        }
      } catch (_) {
        // Ignore JWT errors and continue. The request may still authenticate
        // through a project API key.
      }
    }

    if (apiKey != null && apiKey.isNotEmpty && apiKey != 'null') {
      final tokenRow = await ApiKeyValidator.validate(session, apiKey);
      if (tokenRow != null) {
        final project = await Project.db.findById(session, tokenRow.projectId);
        if (project != null) {
          scopes.add(Scope('project:${project.id!}'));
          scopes.add(Scope('project.read'));
          if (tokenRow.role == 'write' ||
              tokenRow.role == 'editor' ||
              tokenRow.role == 'admin') {
            scopes.add(Scope('project.write'));
          }
          scopes.add(Scope('client:${project.clientId}'));
          userIdentifier ??= 'api-token:${tokenRow.id!}';
          authId ??= 'api-token:${tokenRow.id!}';
        }
      }
    }

    if (userIdentifier == null || authId == null) {
      return null;
    }

    return AuthenticationInfo(
      userIdentifier,
      scopes,
      authId: authId,
    );
  };

  // Start the server.
  await pod.start();

  // Run plugin startup hooks.
  for (final plugin in plugins) {
    await plugin.onStartup(pod);
  }
  await registry.runStartupHooks(pod);
}