trpc-batch-url.ts1.6 KBView on GitHub
/**
 * Reading a tRPC request URL back into the procedures it carries.
 *
 * The client is `httpBatchLink`, so a request's last path segment is a comma-joined list of
 * procedure names — `/api/trpc/mail.send,mail.get` — not a single procedure. Anything deciding
 * "is this request an X?" has to parse that list. Matching the whole pathname against one name is
 * right only when the batch happens to hold exactly one call, which is why the keepalive guard
 * silently stopped protecting sends the moment one shared a batch.
 */

/** The procedures carried by a tRPC request URL, in batch order. */
export function trpcProceduresInUrl(url: string): string[] {
  let pathname: string;
  try {
    pathname = new URL(url, typeof window !== 'undefined' ? window.location.href : undefined)
      .pathname;
  } catch {
    // Relative URL with no base to resolve against — take the part before the query ourselves.
    pathname = url.split('?')[0] ?? '';
  }

  const lastSegment = pathname.split('/').pop() ?? '';
  // The separator arrives percent-encoded on some transports; decode before splitting.
  let decoded = lastSegment;
  try {
    decoded = decodeURIComponent(lastSegment);
  } catch {
    // Malformed escape sequence — the raw segment is the best we have.
  }

  return decoded
    .split(',')
    .map((procedure) => procedure.trim())
    .filter(Boolean);
}

/** True when `procedure` is one of the calls batched into this request. */
export function trpcRequestIncludes(url: string, procedure: string): boolean {
  return trpcProceduresInUrl(url).includes(procedure);
}