All files / sheaves/src types.ts

0% Statements 0/0
0% Branches 0/0
0% Functions 0/0
0% Lines 0/0

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 106 107 108 109 110 111 112 113 114 115                                                                                                                                                                                                                                     
/**
 * Sheaf types: the product decomposition F_sem x F_op.
 *
 * The section (guard + behavior) is the semantic component F_sem.
 * The metadata is the operational component F_op.
 * Effect-equivalence (the sheaf condition) is asserted by the interface:
 * sections covering the same open set produce the same observable result.
 */
 
import type { GET_INTERFACE_GUARD, Methods } from '@endo/exo';
import type { InterfaceGuard } from '@endo/patterns';
import type { MethodSchema } from '@metamask/kernel-utils';
 
/** A section: a capability covering a region of the interface topology. */
export type Section<Core extends Methods = Methods> = Partial<Core> & {
  [K in typeof GET_INTERFACE_GUARD]?: (() => InterfaceGuard) | undefined;
};
 
/**
 * A metadata specification: either a static value or a live function.
 * Evaluated metadata must be a plain object (`{}` means no metadata; primitives
 * must be wrapped, e.g. `{ value: n }`).
 */
export type MetadataSpec<M extends Record<string, unknown>> =
  | { kind: 'constant'; value: M }
  | { kind: 'callable'; fn: (args: unknown[]) => M };
 
/**
 * A provider: a section (F_sem) paired with an optional metadata spec (F_op).
 *
 * This is the input data to sheafify — an (exo, metadata) pair assigned over
 * the open set defined by the exo's guard.
 */
export type Provider<MetaData extends Record<string, unknown>> = {
  exo: Section;
  metadata?: MetadataSpec<MetaData>;
};
 
/**
 * A candidate: a provider with evaluated metadata. The metadata spec has been
 * computed against the invocation args, yielding a concrete plain object. Used
 * internally during dispatch and as the element type of the array received by
 * Policy (where each entry is already a representative of an equivalence class
 * after collapsing). Empty `{}` means no metadata.
 */
export type Candidate<MetaData extends Record<string, unknown>> = {
  exo: Section;
  metadata: MetaData;
};
 
/**
 * Context passed to the policy alongside the candidates.
 *
 * `constraints` holds metadata keys whose values are identical across every
 * candidate — these are topologically determined and not a choice.
 * Typed as `Partial<MetaData>` because the actual partition is runtime-dependent.
 */
export type PolicyContext<MetaData extends Record<string, unknown>> = {
  method: string;
  args: unknown[];
  constraints: Partial<MetaData>;
};
 
/**
 * Policy: a coroutine that yields candidates in preference order and receives
 * the accumulated error list after each failed attempt.
 *
 * Each candidate carries only distinguishing metadata (options); shared metadata
 * (constraints) is delivered separately in the context.
 *
 * The sheaf calls gen.next([]) to prime the coroutine, then gen.next(errors)
 * after each failure, where errors is the ordered list of every error
 * encountered so far. The generator can inspect the history to decide whether
 * to yield another candidate or return (signal exhaustion). The sheaf
 * rethrows the last error when the generator is done.
 *
 * Simple policies that do not need retry logic can ignore the error input:
 *   async function*(candidates) { yield* [...candidates].sort(comparator); }
 */
export type Policy<MetaData extends Record<string, unknown>> = (
  candidates: Candidate<Partial<MetaData>>[],
  context: PolicyContext<MetaData>,
) => AsyncGenerator<Candidate<Partial<MetaData>>, void, unknown[]>;
 
/**
 * A sheaf: an authority manager over a set of providers.
 *
 * Produces dispatch sections via `getSection`, each routing invocations
 * through the providers supplied at construction time.
 */
export type Sheaf<MetaData extends Record<string, unknown>> = {
  /**
   * Produce a dispatch exo over the given guard.
   *
   * Returns `object` rather than a typed exo because the guard is passed
   * dynamically at call time — TypeScript cannot propagate the method
   * signatures through `Sheaf<M>` without knowing the specific guard.
   * Cast to the interface type at the call site once you know the guard.
   */
  getSection: (opts: {
    guard: InterfaceGuard;
    policy: Policy<MetaData>;
  }) => object;
  /**
   * Produce a discoverable dispatch exo over the given guard.
   *
   * Returns `object` for the same reason as `getSection`.
   */
  getDiscoverableSection: (opts: {
    guard: InterfaceGuard;
    policy: Policy<MetaData>;
    schema: Record<string, MethodSchema>;
  }) => object;
};