All files / service-discovery-types/src matcher.ts

100% Statements 3/3
100% Branches 0/0
100% Functions 0/0
100% Lines 3/3

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105                                                1x                         1x         1x                                                                                                                            
/**
 * Service matcher interface.
 *
 * A {@link ServiceMatcher} aggregates service descriptions and helps
 * consumers find services that satisfy their needs. The matcher is a
 * remotable; its JSON-serializable inputs and outputs have runtime
 * validators.
 */
 
import { array, exactOptional, object, string } from '@metamask/superstruct';
import type { Infer, Struct } from '@metamask/superstruct';
 
import type { ContactPoint, RegistrationToken } from './contact.ts';
import { ServiceDescriptionStruct } from './service-description.ts';
import type { ServiceDescription } from './service-description.ts';
 
/**
 * A consumer's expression of what it is looking for. Intentionally loose —
 * the matcher determines how this is interpreted.
 */
export type ServiceQuery = {
  description: string;
};
 
export const ServiceQueryStruct: Struct<ServiceQuery> = object({
  description: string(),
});
 
/**
 * A candidate service returned by a matcher query.
 */
export type ServiceMatch = {
  description: ServiceDescription;
  /** Matcher's natural-language rationale for this match. */
  rationale?: string;
};
 
export const ServiceMatchStruct: Struct<ServiceMatch> = object({
  description: ServiceDescriptionStruct,
  rationale: exactOptional(string()),
});
 
export const ServiceMatchListStruct: Struct<ServiceMatch[]> =
  array(ServiceMatchStruct);
 
export type ServiceMatchList = Infer<typeof ServiceMatchListStruct>;
 
// Two-way drift guards: assert that the hand-written types match the
// shapes the structs infer, so adding a field to one without the other
// fails to compile. (Mirrors the pattern in `service-description.ts`.)
type _AssertSameShape<Left, Right> = Left extends Right
  ? Right extends Left
    ? true
    : never
  : never;
 
export type _AssertServiceQuery = _AssertSameShape<
  Infer<typeof ServiceQueryStruct>,
  ServiceQuery
>;
export type _AssertServiceMatch = _AssertSameShape<
  Infer<typeof ServiceMatchStruct>,
  ServiceMatch
>;
 
/**
 * The matcher's public interface.
 *
 * Registration callers present a `registrationToken` which the matcher uses
 * to call back into `ContactPoint.confirmServiceRegistration` on the
 * service's contact endpoint, verifying the registration is legitimate
 * before accepting it.
 */
export type ServiceMatcher = {
  /** Register a service by supplying its description directly. */
  registerService(
    description: ServiceDescription,
    registrationToken: RegistrationToken,
  ): Promise<void>;
 
  /**
   * Register a service by contact URL; the matcher resolves the URL and
   * fetches the description itself.
   */
  registerServiceByUrl(
    contactUrl: string,
    registrationToken: RegistrationToken,
  ): Promise<void>;
 
  /**
   * Register a service by direct ocap reference; the matcher calls
   * `getServiceDescription()` on the contact endpoint.
   */
  registerServiceByRef(
    contact: ContactPoint,
    registrationToken: RegistrationToken,
  ): Promise<void>;
 
  /**
   * Query the matcher for services satisfying a described need. Returns a
   * (possibly empty) ranked list of candidate matches.
   */
  findServices(query: ServiceQuery): Promise<ServiceMatch[]>;
};