dvBillingCustomerKey function

String dvBillingCustomerKey(
  1. Object customer
)

The key entitlements and usage are stored under for customer.

Providers took customer.toString(). For a String that is an identity; for an ordinary Dart object it is the constant "Instance of 'User'", so passing the logged-in user -- the obvious thing to do, and what a parameter typed Object invites -- filed every user in the application under one key. One person subscribes, everybody has the plan, and nothing anywhere reports a problem.

So an identity is required. A DVBillingCustomer states one, a String or a number is one, and a class with a meaningful toString has one. An object with the default toString has none, and gets an error rather than a shared key: keying on the type name is the same bug as the hash code this replaced, with better spelling.

Implementation

String dvBillingCustomerKey(Object customer) {
  final String key = customer is DVBillingCustomer
      ? customer.billingCustomerId
      : customer.toString();

  if (key.isEmpty) {
    throw ArgumentError.value(
      customer,
      'customer',
      'a billing customer needs an identifier, and this one is empty. An '
          'empty key is one key, shared by everybody who has none',
    );
  }
  if (RegExp(r"^Instance of '.*'$").hasMatch(key)) {
    throw ArgumentError.value(
      customer,
      'customer',
      'a ${customer.runtimeType} has no billing identity: its toString is '
          'the same text for every instance, so entitlements and usage would '
          'be shared by every ${customer.runtimeType} in the application. '
          'Implement DVBillingCustomer on it, or pass the provider customer '
          'id',
    );
  }
  return key;
}