{"version":3,"sources":["../../src/direct/personal-server-read.ts"],"sourcesContent":["/**\n * Personal Server data-read request builder and the 402 -> escrow-pay -> retry loop.\n *\n * @remarks\n * The read targets the Personal Server data path (`/v1/data/{scope}`),\n * authenticates with a Web3Signed header (built on {@link buildWeb3SignedHeader}),\n * and — on `402 Payment Required` — signs the challenged escrow operation and\n * retries once.\n *\n * The 402 body is parsed into a validated grant or receipt-bound data-access\n * operation, which drives the escrow settlement.\n *\n * @category Direct\n * @module direct/personal-server-read\n */\n\nimport { buildWeb3SignedHeader } from \"../auth/web3-signed-builder\";\nimport type { Web3SignedSignFn } from \"../auth/web3-signed-builder\";\nimport {\n  NATIVE_ASSET_ADDRESS,\n  type EscrowAccessRecord,\n} from \"../protocol/escrow\";\nimport {\n  buildEscrowPaymentHeader,\n  DATA_ACCESS_OP_TYPE,\n  GRANT_OP_TYPE,\n  paymentResponseMetadataFromHeader,\n  type EscrowPaymentHeaderConfig,\n} from \"./escrow-payment\";\nimport { PaymentRequiredError, PersonalServerReadError } from \"./errors\";\nimport { DataPointDeletedError } from \"../errors\";\nimport {\n  isDataPointTombstone,\n  tombstoneDeletedAt,\n} from \"../protocol/data-point-deletion\";\nimport { readJsonValue } from \"../utils/response-body\";\nimport type {\n  DirectPaymentResponseMetadata,\n  PersonalServerDataAccessPaymentOperation,\n  PersonalServerPaymentOperation,\n} from \"./types\";\n\n/** Minimal `Response`-like shape so the read loop is testable without a DOM. */\nexport interface FetchResponseLike {\n  ok: boolean;\n  status: number;\n  statusText: string;\n  headers: { get(name: string): string | null };\n  json(): Promise<unknown>;\n  text(): Promise<string>;\n}\n\n/** Minimal `fetch` signature accepted by {@link readPersonalServerData}. */\nexport type PersonalServerFetch = (\n  input: string,\n  init: {\n    method: string;\n    headers: Record<string, string>;\n  },\n) => Promise<FetchResponseLike>;\n\n/** A built, ready-to-send Personal Server data read request. */\nexport interface PersonalServerDataReadRequest {\n  /** Absolute URL of the read endpoint. */\n  url: string;\n  /** HTTP method (always `\"GET\"`). */\n  method: \"GET\";\n  /** Request path used in the Web3Signed `uri` claim (e.g. `/v1/data/{scope}`). */\n  path: string;\n  /** Headers including the Web3Signed `Authorization` value. */\n  headers: Record<string, string>;\n}\n\n/**\n * Transport-level retry knobs for {@link readPersonalServerData}.\n *\n * @remarks\n * Applies only when the underlying `fetch` **throws** (connection reset, DNS,\n * socket died mid-handshake — the browser-PS relay drop window). A received\n * HTTP response is never retried here: 402 has its own payment loop and other\n * statuses are surfaced to the caller unchanged.\n */\nexport interface PersonalServerTransportRetryOptions {\n  /** Total attempts including the first (default 3). `1` disables retries. */\n  attempts?: number;\n  /** Delay before the first retry (ms); doubles per retry (default 1_000). */\n  initialDelayMs?: number;\n  /** Cap on the between-retry delay (ms, default 5_000). */\n  maxDelayMs?: number;\n}\n\nconst TRANSPORT_RETRY_DEFAULTS: Required<PersonalServerTransportRetryOptions> =\n  {\n    attempts: 3,\n    initialDelayMs: 1_000,\n    maxDelayMs: 5_000,\n  };\n\n/** Clamp a caller-supplied attempt count to a finite integer >= 1. */\nfunction resolveAttempts(attempts: number): number {\n  return Number.isFinite(attempts) ? Math.max(1, Math.floor(attempts)) : 1;\n}\n\n/** An aborted request is the caller's intent to stop — never retry it. */\nfunction isAbortError(error: unknown): boolean {\n  return error instanceof Error && error.name === \"AbortError\";\n}\n\nconst sleep = (ms: number) =>\n  new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/**\n * Run a fetch with bounded transport retries.\n *\n * Each attempt rebuilds the request via `buildRequest` so the Web3Signed\n * header is freshly signed (local app-key signature — cheap), while letting\n * the caller pin anything that must NOT be regenerated across attempts\n * (an already-signed `X-PAYMENT` header keeps its paymentNonce, so a retry\n * can never mint a second escrow payment for the same read).\n */\nasync function fetchWithTransportRetry(\n  fetchFn: PersonalServerFetch,\n  buildRequest: () => Promise<{\n    url: string;\n    method: string;\n    headers: Record<string, string>;\n  }>,\n  retry: Required<PersonalServerTransportRetryOptions>,\n): Promise<FetchResponseLike> {\n  const attempts = resolveAttempts(retry.attempts);\n  let lastError: unknown;\n  for (let attempt = 0; attempt < attempts; attempt += 1) {\n    if (attempt > 0) {\n      await sleep(\n        Math.min(retry.maxDelayMs, retry.initialDelayMs * 2 ** (attempt - 1)),\n      );\n    }\n    const request = await buildRequest();\n    try {\n      return await fetchFn(request.url, {\n        method: request.method,\n        headers: request.headers,\n      });\n    } catch (error) {\n      // An abort is a deliberate cancellation, not a flaky tunnel — surface it\n      // immediately instead of burning attempts (and backoff) on it.\n      if (isAbortError(error)) {\n        throw error;\n      }\n      lastError = error;\n    }\n  }\n  throw lastError;\n}\n\n/** Outcome of {@link readPersonalServerData}. */\nexport interface PersonalServerReadResult {\n  /** The decoded JSON payload returned by the Personal Server. */\n  data: unknown;\n  /**\n   * Shape-validated but unauthenticated payment metadata echoed by the\n   * Personal Server. Never treat this field as accounting proof.\n   */\n  payment?: DirectPaymentResponseMetadata;\n}\n\nfunction stripTrailingSlash(url: string): string {\n  return url.replace(/\\/+$/, \"\");\n}\n\n/** Compute the data path for a scope (`/v1/data/{scope}`). */\nexport function dataPathForScope(scope: string): string {\n  return `/v1/data/${encodeURIComponent(scope)}`;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | undefined {\n  return value && typeof value === \"object\" && !Array.isArray(value)\n    ? (value as Record<string, unknown>)\n    : undefined;\n}\n\nfunction stringField(\n  record: Record<string, unknown> | undefined,\n  field: string,\n): string | undefined {\n  const value = record?.[field];\n  return typeof value === \"string\" ? value : undefined;\n}\n\nfunction parseAccessRecord(value: unknown): EscrowAccessRecord | undefined {\n  const record = asRecord(value);\n  const dataPointId = stringField(record, \"dataPointId\");\n  const version = stringField(record, \"version\");\n  const accessor = stringField(record, \"accessor\");\n  const recordId = stringField(record, \"recordId\");\n  const signature = stringField(record, \"signature\");\n\n  if (!dataPointId || !version || !accessor || !recordId || !signature) {\n    return undefined;\n  }\n\n  return {\n    dataPointId: dataPointId as `0x${string}`,\n    version,\n    accessor: accessor as `0x${string}`,\n    recordId: recordId as `0x${string}`,\n    signature: signature as `0x${string}`,\n  };\n}\n\nfunction isBytes32Hex(value: string): boolean {\n  return /^0x[0-9a-fA-F]{64}$/.test(value);\n}\n\nconst UINT256_MAX = (1n << 256n) - 1n;\n\nfunction isAddressHex(value: string): boolean {\n  return /^0x[0-9a-fA-F]{40}$/.test(value);\n}\n\nfunction isUint256Decimal(value: string, allowZero: boolean): boolean {\n  const pattern = allowZero ? /^(0|[1-9]\\d*)$/ : /^[1-9]\\d*$/;\n  return (\n    value.length <= UINT256_MAX.toString().length &&\n    pattern.test(value) &&\n    BigInt(value) <= UINT256_MAX\n  );\n}\n\nfunction isValidDataAccessRecord(record: EscrowAccessRecord): boolean {\n  return (\n    isBytes32Hex(record.dataPointId) &&\n    isUint256Decimal(record.version, false) &&\n    isAddressHex(record.accessor) &&\n    isBytes32Hex(record.recordId) &&\n    /^0x[0-9a-fA-F]{130}$/.test(record.signature)\n  );\n}\n\nfunction parseLegacyGrantOperation(params: {\n  challengeGrantId?: string;\n  challengeOpId?: string;\n  challengeOpType?: string;\n  grantId: string;\n}): { opType: typeof GRANT_OP_TYPE; opId: string } {\n  const { challengeGrantId, challengeOpId, challengeOpType, grantId } = params;\n\n  const opType = challengeOpType ?? GRANT_OP_TYPE;\n  if (opType !== GRANT_OP_TYPE) {\n    throw new PersonalServerReadError(\n      \"Personal Server payment challenge used an unsupported escrow op type\",\n      402,\n      { opType: challengeOpType },\n    );\n  }\n\n  const opId = challengeOpId ?? challengeGrantId ?? grantId;\n\n  if (!opId || !isBytes32Hex(opId)) {\n    throw new PersonalServerReadError(\n      \"Personal Server payment challenge used an invalid escrow op id\",\n      402,\n      { opId },\n    );\n  }\n\n  if (opId.toLowerCase() !== grantId.toLowerCase()) {\n    throw new PersonalServerReadError(\n      \"Personal Server payment challenge did not match the requested grant\",\n      402,\n      { opId, grantId },\n    );\n  }\n\n  return { opType: GRANT_OP_TYPE, opId };\n}\n\nfunction hasDataAccessMarker(body: Record<string, unknown>): boolean {\n  if (stringField(body, \"opType\") === DATA_ACCESS_OP_TYPE) return true;\n  return (\n    Array.isArray(body.accepts) &&\n    body.accepts.some((value) => {\n      const accept = asRecord(value);\n      return (\n        stringField(asRecord(accept?.message), \"opType\") === DATA_ACCESS_OP_TYPE\n      );\n    })\n  );\n}\n\nfunction parseCanonicalDataAccessAccept(\n  value: unknown,\n): Omit<PersonalServerDataAccessPaymentOperation, \"grantId\" | \"raw\"> | null {\n  const accept = asRecord(value);\n  const message = asRecord(accept?.message);\n  if (\n    stringField(accept, \"scheme\") !== \"vana-escrow-grant\" ||\n    stringField(message, \"opType\") !== DATA_ACCESS_OP_TYPE\n  ) {\n    return null;\n  }\n\n  const network = stringField(accept, \"network\");\n  const payerAddress = stringField(message, \"payerAddress\");\n  const opId = stringField(message, \"opId\");\n  const asset = stringField(message, \"asset\");\n  const amount = stringField(message, \"amount\");\n  const paymentNonce = stringField(message, \"paymentNonce\");\n  const accessRecord = parseAccessRecord(accept?.accessRecord);\n  const acceptAsset = stringField(accept, \"asset\");\n  const acceptAmount = stringField(accept, \"amount\");\n\n  if (\n    !network ||\n    !payerAddress ||\n    !isAddressHex(payerAddress) ||\n    !opId ||\n    !isBytes32Hex(opId) ||\n    !asset ||\n    !isAddressHex(asset) ||\n    !amount ||\n    !isUint256Decimal(amount, true) ||\n    !paymentNonce ||\n    !isUint256Decimal(paymentNonce, false) ||\n    !accessRecord ||\n    !isValidDataAccessRecord(accessRecord) ||\n    payerAddress.toLowerCase() !== accessRecord.accessor.toLowerCase() ||\n    opId.toLowerCase() !== accessRecord.recordId.toLowerCase() ||\n    !acceptAsset ||\n    acceptAsset.toLowerCase() !== asset.toLowerCase() ||\n    acceptAmount !== amount\n  ) {\n    return null;\n  }\n\n  return {\n    opType: DATA_ACCESS_OP_TYPE,\n    opId,\n    network,\n    paymentNonce,\n    accessRecord,\n    asset,\n    amount,\n  };\n}\n\nfunction parseCanonicalDataAccessPayment(params: {\n  body: Record<string, unknown>;\n  grantId: string;\n  raw: unknown;\n}): PersonalServerDataAccessPaymentOperation | undefined {\n  const { body, grantId, raw } = params;\n  if (body.x402Version !== 1 || body.error !== \"PAYMENT_REQUIRED\") {\n    throw new PersonalServerReadError(\n      \"Personal Server data-access payment response was not a canonical x402 challenge\",\n      402,\n    );\n  }\n\n  const operation = Array.isArray(body.accepts)\n    ? body.accepts\n        .map(parseCanonicalDataAccessAccept)\n        .find((candidate) => candidate !== null)\n    : undefined;\n  if (!operation) {\n    return undefined;\n  }\n\n  return { grantId, raw, ...operation };\n}\n\nfunction preferredLegacyAccept(body: Record<string, unknown>) {\n  if (!Array.isArray(body.accepts)) return undefined;\n  return body.accepts.map(asRecord).find((accept) => {\n    const message = asRecord(accept?.message);\n    return (\n      stringField(accept, \"scheme\") === \"vana-escrow-grant\" &&\n      stringField(message, \"opType\") === GRANT_OP_TYPE\n    );\n  });\n}\n\n/**\n * Build a Web3Signed-authenticated Personal Server data read request.\n *\n * @param params - Personal Server URL, scope, grant id, and an EIP-191 signer.\n * @returns The request URL, method, path, and headers (including `Authorization`).\n */\nexport async function buildPersonalServerDataReadRequest(params: {\n  /** Base URL of the user's Personal Server. */\n  personalServerUrl: string;\n  /** Scope to read (e.g. `\"icloud_notes.notes\"`). */\n  scope: string;\n  /** Grant id authorizing the read. */\n  grantId: string;\n  /** EIP-191 signer for the Web3Signed header (the app key). */\n  signMessage: Web3SignedSignFn;\n}): Promise<PersonalServerDataReadRequest> {\n  const base = stripTrailingSlash(params.personalServerUrl);\n  const path = dataPathForScope(params.scope);\n  const authorization = await buildWeb3SignedHeader({\n    signMessage: params.signMessage,\n    aud: base,\n    method: \"GET\",\n    uri: path,\n    grantId: params.grantId,\n  });\n  const headers: Record<string, string> = {\n    Authorization: authorization,\n    Accept: \"application/json\",\n  };\n  return { url: `${base}${path}`, method: \"GET\", path, headers };\n}\n\n/**\n * Parse a `402 Payment Required` body into a validated payment operation.\n *\n * @remarks\n * Accepts a few field spellings and falls back to the read's own grantId and the\n * native asset when a field is absent from a legacy grant challenge.\n *\n * Receipt-bound `data_access` uses a fail-closed canonical path: one compatible\n * `accepts` entry must contain the scheme, network, message, and complete\n * receipt. Its positive uint256 `paymentNonce` is mandatory because the\n * Personal Server encodes challenge freshness in that nonce and checks it on\n * retry. This parser shape-validates the receipt and binds `opId` to `recordId`;\n * it does not recover or verify the server signature.\n *\n * @param res - The 402 response.\n * @param grantId - The grant id of the read (default legacy grant `opId`).\n * @returns The parsed payment requirement.\n */\nexport async function parsePersonalServerPaymentRequired(\n  res: FetchResponseLike,\n  grantId: string,\n): Promise<PersonalServerPaymentOperation> {\n  let raw: unknown = undefined;\n  try {\n    raw = await res.json();\n  } catch {\n    raw = undefined;\n  }\n  const body = asRecord(raw) ?? {};\n  if (hasDataAccessMarker(body)) {\n    const dataAccessOperation = parseCanonicalDataAccessPayment({\n      body,\n      grantId,\n      raw,\n    });\n    if (dataAccessOperation) return dataAccessOperation;\n  }\n\n  // Legacy grant challenges predate the canonical x402 envelope. Retain their\n  // field fallbacks only for truly flat bodies. Once an accepts envelope is\n  // present, validate its canonical framing and select only a compatible offer.\n  const hasAcceptsEnvelope = Object.prototype.hasOwnProperty.call(\n    body,\n    \"accepts\",\n  );\n  if (\n    hasAcceptsEnvelope &&\n    (body.x402Version !== 1 || body.error !== \"PAYMENT_REQUIRED\")\n  ) {\n    throw new PersonalServerReadError(\n      \"Personal Server grant payment response was not a canonical x402 challenge\",\n      402,\n    );\n  }\n  const accept = preferredLegacyAccept(body);\n  if (hasDataAccessMarker(body) && !accept) {\n    throw new PersonalServerReadError(\n      \"Personal Server data-access payment challenge was untrusted or incomplete\",\n      402,\n    );\n  }\n  if (hasAcceptsEnvelope && !accept) {\n    throw new PersonalServerReadError(\n      \"Personal Server grant payment challenge had no compatible escrow offer\",\n      402,\n    );\n  }\n\n  if (accept) {\n    const message = asRecord(accept.message);\n    const network = stringField(accept, \"network\");\n    const payerAddress = stringField(message, \"payerAddress\");\n    const opId = stringField(message, \"opId\");\n    const asset = stringField(message, \"asset\");\n    const amount = stringField(message, \"amount\");\n    const paymentNonce = stringField(message, \"paymentNonce\");\n    const acceptAsset = stringField(accept, \"asset\");\n    const acceptAmount = stringField(accept, \"amount\");\n    const accessRecord = parseAccessRecord(accept.accessRecord);\n    const hasAccessRecord = accept.accessRecord !== undefined;\n    if (\n      !network ||\n      !payerAddress ||\n      !isAddressHex(payerAddress) ||\n      !opId ||\n      !isBytes32Hex(opId) ||\n      !asset ||\n      !isAddressHex(asset) ||\n      !amount ||\n      !isUint256Decimal(amount, true) ||\n      !paymentNonce ||\n      !isUint256Decimal(paymentNonce, false) ||\n      !acceptAsset ||\n      acceptAsset.toLowerCase() !== asset.toLowerCase() ||\n      acceptAmount !== amount ||\n      (hasAccessRecord &&\n        (!accessRecord ||\n          !isValidDataAccessRecord(accessRecord) ||\n          accessRecord.accessor.toLowerCase() !==\n            payerAddress.toLowerCase())) ||\n      (amount === \"0\" && !accessRecord)\n    ) {\n      throw new PersonalServerReadError(\n        \"Personal Server grant payment challenge was untrusted or incomplete\",\n        402,\n      );\n    }\n    const operation = parseLegacyGrantOperation({\n      challengeOpId: opId,\n      challengeOpType: stringField(message, \"opType\"),\n      grantId,\n    });\n    return {\n      grantId,\n      ...operation,\n      network,\n      paymentNonce,\n      asset,\n      amount,\n      raw,\n      ...(accessRecord ? { accessRecord } : {}),\n    };\n  }\n\n  const challengeGrantId = stringField(body, \"grantId\");\n  const challengeOpId = stringField(body, \"opId\");\n  const challengeOpType = stringField(body, \"opType\");\n\n  const accessRecord = parseAccessRecord(body.accessRecord);\n  const operation = parseLegacyGrantOperation({\n    challengeGrantId,\n    challengeOpId,\n    challengeOpType,\n    grantId,\n  });\n\n  const amountValue =\n    stringField(body, \"amount\") ??\n    stringField(body, \"maxAmountRequired\") ??\n    \"0\";\n  const payment = {\n    grantId,\n    network: stringField(body, \"network\"),\n    paymentNonce: stringField(body, \"paymentNonce\"),\n    asset: stringField(body, \"asset\") ?? NATIVE_ASSET_ADDRESS,\n    amount: amountValue,\n    raw,\n  };\n  return {\n    ...payment,\n    ...operation,\n    ...(accessRecord ? { accessRecord } : {}),\n  };\n}\n\nfunction hasPositiveAmount(amount: string): boolean {\n  if (!/^\\d+$/.test(amount)) return false;\n  return BigInt(amount) > 0n;\n}\n\nfunction isReceiptOnlyGrantAcknowledgment(\n  required: PersonalServerPaymentOperation,\n  payerAddress: string,\n): boolean {\n  return (\n    required.opType === GRANT_OP_TYPE &&\n    required.amount === \"0\" &&\n    required.accessRecord !== undefined &&\n    isValidDataAccessRecord(required.accessRecord) &&\n    required.accessRecord.accessor.toLowerCase() === payerAddress.toLowerCase()\n  );\n}\n\n/**\n * Read approved data from a Personal Server, settling a 402 via escrow.\n *\n * @remarks\n * Sends a Web3Signed-authenticated `GET /v1/data/{scope}`. On `402`, parses what\n * is owed, authorizes the challenged escrow operation, and retries once. If\n * escrow is not configured, throws {@link PaymentRequiredError} carrying the\n * parsed requirement so callers can debug amount/asset.\n *\n * Transport failures (fetch throwing — the browser-PS relay reconnect window)\n * are retried with backoff per `transportRetry` (default 3 attempts). The paid\n * retry reuses the already-signed `X-PAYMENT` header, so transport retries can\n * never double-pay.\n *\n * @param params - Connection details, app signer, optional escrow config and fetch.\n * @returns `{ data, payment? }`.\n */\nexport async function readPersonalServerData(params: {\n  personalServerUrl: string;\n  scope: string;\n  grantId: string;\n  payerAddress: `0x${string}`;\n  signMessage: Web3SignedSignFn;\n  escrow?: EscrowPaymentHeaderConfig;\n  fetchFn?: PersonalServerFetch;\n  transportRetry?: PersonalServerTransportRetryOptions;\n}): Promise<PersonalServerReadResult> {\n  const fetchFn =\n    params.fetchFn ?? (globalThis.fetch as unknown as PersonalServerFetch);\n  if (!fetchFn) {\n    throw new PersonalServerReadError(\n      \"No fetch implementation available for Personal Server read\",\n    );\n  }\n  const transportRetry = {\n    ...TRANSPORT_RETRY_DEFAULTS,\n    ...params.transportRetry,\n  };\n\n  const buildRequest = () =>\n    buildPersonalServerDataReadRequest({\n      personalServerUrl: params.personalServerUrl,\n      scope: params.scope,\n      grantId: params.grantId,\n      signMessage: params.signMessage,\n    });\n\n  let res = await fetchWithTransportRetry(\n    fetchFn,\n    buildRequest,\n    transportRetry,\n  );\n\n  let payment: DirectPaymentResponseMetadata | undefined;\n\n  if (res.status === 402) {\n    const required = await parsePersonalServerPaymentRequired(\n      res,\n      params.grantId,\n    );\n    if (!params.escrow) {\n      throw new PaymentRequiredError(\n        \"Personal Server requires payment but no escrow config is set\",\n        {\n          scope: params.scope,\n          grantId: required.grantId,\n          asset: required.asset,\n          amount: required.amount,\n        },\n      );\n    }\n\n    if (\n      required.opType === GRANT_OP_TYPE &&\n      !hasPositiveAmount(required.amount) &&\n      !isReceiptOnlyGrantAcknowledgment(required, params.payerAddress)\n    ) {\n      throw new PaymentRequiredError(\n        \"Personal Server payment challenge included neither a positive amount nor a valid access receipt\",\n        {\n          scope: params.scope,\n          grantId: required.grantId,\n          asset: required.asset,\n          amount: required.amount,\n        },\n      );\n    }\n\n    const paymentHeader = await buildEscrowPaymentHeader({\n      payerAddress: params.payerAddress,\n      required,\n      config: params.escrow,\n    });\n\n    // Re-sign and retry with x402 payment proof for the Personal Server to\n    // validate. The payment header is built exactly once: transport retries\n    // below re-sign only the Web3Signed auth and resend the SAME X-PAYMENT\n    // (same paymentNonce), so a dropped tunnel cannot mint a second payment.\n    res = await fetchWithTransportRetry(\n      fetchFn,\n      async () => {\n        const retry = await buildRequest();\n        return {\n          ...retry,\n          headers: { ...retry.headers, \"X-PAYMENT\": paymentHeader },\n        };\n      },\n      transportRetry,\n    );\n\n    if (res.status === 402) {\n      throw new PaymentRequiredError(\n        \"Personal Server still requires payment after escrow settlement\",\n        {\n          scope: params.scope,\n          grantId: required.grantId,\n          asset: required.asset,\n          amount: required.amount,\n          payment,\n        },\n      );\n    }\n  }\n\n  // 410 = the scope was tombstoned by its owner. Typed so builders can\n  // branch on \"gone\" without parsing a generic read failure.\n  if (res.status === 410) {\n    throw new DataPointDeletedError(\n      `Personal Server scope '${params.scope}' has been deleted`,\n      {\n        scope: params.scope,\n        deletedAt: tombstoneDeletedAt(await readJsonValue(res)),\n      },\n    );\n  }\n\n  if (!res.ok) {\n    const detail = await res.text().catch(() => \"\");\n    throw new PersonalServerReadError(\n      `Personal Server read failed: ${res.status} ${res.statusText}`,\n      res.status,\n      { scope: params.scope, body: detail.slice(0, 500) },\n    );\n  }\n\n  payment = paymentResponseMetadataFromHeader(\n    res.headers.get(\"X-PAYMENT-RESPONSE\"),\n  );\n  const data: unknown = await res.json();\n  // Never return a tombstone as data, even on a 200 that carries the deleted\n  // row (deletedAt / tombstone hash pair).\n  if (isDataPointTombstone(data)) {\n    throw new DataPointDeletedError(\n      `Personal Server scope '${params.scope}' has been deleted`,\n      { scope: params.scope, deletedAt: tombstoneDeletedAt(data) },\n    );\n  }\n  return { data, payment };\n}\n"],"mappings":"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","names":["import_errors","accessRecord","operation"]}