{"version":3,"sources":["../../src/protocol/personal-server-write.ts"],"sourcesContent":["/**\n * Builder-side client for the Personal Server Write API.\n *\n * @remarks\n * A builder holding a write-grant (a grant whose scope entries carry the\n * `write:` prefix, see {@link formatScopeEntry}) writes into a user's Personal\n * Server in two steps:\n *\n * 1. {@link openWriteSession}: `POST /v1/write/session` with a Web3Signed\n *    handshake that carries the grant id as a signed claim. The Personal\n *    Server verifies the builder key against the grant and mints a\n *    short-lived bearer token bound to `{ builder, grantId }`.\n * 2. {@link writeData}: `POST /v1/data/:scope` with that bearer plus an\n *    `X-Vana-Write-Signature` proof, a second Web3Signed signature over the\n *    representation the Personal Server will store, again carrying the grant\n *    id as a signed claim. The Personal Server stores the proof with the\n *    record under the reserved `$writtenBy` key so anyone holding the record\n *    can verify who wrote it.\n *\n * What the proof covers: a JSON write signs the request body, which must be\n * the compact `JSON.stringify` form (the server rejects anything else with\n * `WRITE_BODY_NOT_CANONICAL`); a binary write signs the `$binary` record the\n * server stores for the bytes and their representation headers\n * ({@link binaryWriteSignedBytes}), not the raw bytes. Every proof is\n * single-use: a retry after a lost response signs a fresh proof.\n *\n * Derivatives name their sources through `lineage` (see\n * {@link deriveDataPointId}): for a JSON write the ids are the top-level\n * `lineage` field of the body (inside the signed bytes); for a binary write\n * they are the `lineage` field of the `X-Vana-Metadata` JSON (inside the\n * signed `$binary` record). The server validates them and mirrors them under\n * the reserved `$lineage` key. Callers never send `$writtenBy` or `$lineage`.\n *\n * @category Protocol\n */\n\nimport { sha256 } from \"@noble/hashes/sha2\";\nimport { bytesToHex, isAddress, type Address, type Hex } from \"viem\";\nimport { z } from \"zod\";\nimport { buildWeb3SignedHeader } from \"../auth/web3-signed-builder\";\nimport {\n  type PersonalServerWriteError,\n  WriteConflictError,\n  WriteForbiddenError,\n  WriteLineageError,\n  WriteRejectedError,\n  WriteRequestError,\n  WriteSessionError,\n  WriteSessionExpiredError,\n  WriteUnauthorizedError,\n} from \"../errors\";\nimport { toBase64 } from \"../utils/encoding\";\nimport { IngestResponseSchema, type IngestResponse } from \"./data-file\";\nimport {\n  assertDerivedScopeNaming,\n  deriveDataPointId,\n  isDataPointId,\n} from \"./lineage\";\nimport {\n  isRecord,\n  readPersonalServerErrorBody,\n} from \"./personal-server-error-body\";\nimport { scopeMatchesPattern } from \"./scopes\";\nimport {\n  errorMessage,\n  normalizeBaseUrl,\n  proofKeyFor,\n  resolveFetch,\n  sendWithFreshProof,\n  type WriteTransportRetryOptions,\n} from \"./write-request\";\nimport {\n  resolveWriteSigner,\n  type ResolveWriteSignerOptions,\n  type WriteSigner,\n  type WriteSignerSource,\n} from \"./write-signer\";\n\nexport type { WriteTransportRetryOptions };\n\n/** Path of the write-session handshake. */\nexport const WRITE_SESSION_PATH = \"/v1/write/session\";\n/** Header carrying the builder's per-write payload proof. */\nexport const WRITE_SIGNATURE_HEADER = \"X-Vana-Write-Signature\";\n/** Header carrying caller metadata (and `lineage`) for a binary write. */\nexport const WRITE_METADATA_HEADER = \"X-Vana-Metadata\";\n/** Field the lineage source ids travel in (body for JSON, metadata for binary). */\nexport const LINEAGE_FIELD = \"lineage\";\n/** The most sources one record may cite. */\nexport const MAX_LINEAGE_SOURCES = 256;\n/** Header carrying the filename of a binary write (printable ASCII names). */\nexport const WRITE_FILENAME_HEADER = \"X-Filename\";\n/**\n * Header carrying a filename the `X-Filename` header cannot: the Personal\n * Server percent-decodes `filename*=UTF-8''...` (RFC 5987).\n */\nexport const WRITE_CONTENT_DISPOSITION_HEADER = \"Content-Disposition\";\n/** Reserved record key the Personal Server stamps builder attribution into. */\nexport const WRITER_ATTRIBUTION_KEY = \"$writtenBy\";\n/** Reserved record key the Personal Server stamps lineage sources into. */\nexport const LINEAGE_KEY = \"$lineage\";\n/** Record keys a builder must never send. */\nexport const RESERVED_WRITE_KEYS: readonly string[] = [\n  WRITER_ATTRIBUTION_KEY,\n  LINEAGE_KEY,\n];\n\n/** An open write session: the bearer token plus what it was minted for. */\nexport interface WriteSession {\n  /** Personal Server origin, without a trailing slash. */\n  personalServerUrl: string;\n  /** Web3Signed audience every proof under this session is addressed to. */\n  audience: string;\n  /** The write-grant the session is bound to. */\n  grantId: string;\n  /** The bearer token (`vana_write_...`). */\n  accessToken: string;\n  /** Unix milliseconds after which the token is no longer accepted. */\n  expiresAt: number;\n  /** Write patterns (prefix stripped) the session may write into. */\n  writeScopes: readonly string[];\n  /** The builder key the session was opened with; signs every write proof. */\n  signer: WriteSigner;\n}\n\nexport interface OpenWriteSessionParams extends ResolveWriteSignerOptions {\n  /** Personal Server origin, e.g. `https://ps.example.com`. */\n  personalServerUrl: string;\n  /** Builder key: a viem `LocalAccount`, `WalletClient`, or `{ signMessage }`. */\n  signer: WriteSignerSource;\n  /** The write-grant issued to the builder. */\n  grantId: string;\n  /** Web3Signed audience; defaults to `personalServerUrl`. */\n  audience?: string;\n  /** `fetch` to use; defaults to `globalThis.fetch`. */\n  fetch?: typeof fetch;\n  /** Extra request headers. */\n  headers?: HeadersInit;\n  retry?: WriteTransportRetryOptions;\n}\n\n/** A lineage source: a data point id, or the pair it is derived from. */\nexport type LineageSource = Hex | { ownerAddress: Address; scope: string };\n\n/** Bytes to store as an unstructured (binary) record. */\nexport interface WriteBinaryPayload {\n  bytes: Uint8Array;\n  /** Media type, e.g. `application/pdf`. Parameters are dropped when stored. */\n  contentType: string;\n  /**\n   * Stored with the record. Sent as `X-Filename` when it is printable ASCII,\n   * otherwise as `Content-Disposition: attachment; filename*=UTF-8''...`,\n   * which the Personal Server decodes back to the same string. Must not have\n   * leading or trailing whitespace (HTTP would strip it and the signed\n   * representation would no longer match).\n   */\n  filename?: string;\n}\n\ninterface WriteDataBaseParams {\n  session: WriteSession;\n  /**\n   * The scope to write into; must match one of the session's write patterns.\n   * A derived scope must not share its first dot-segment with any source's\n   * scope (the server rejects it with `LINEAGE_SCOPE_UNDER_SOURCE_PREFIX`):\n   * put derivatives in the app's own namespace.\n   */\n  scope: string;\n  /**\n   * The data points this record was derived from: ids\n   * ({@link deriveDataPointId}) or `{ ownerAddress, scope }` pairs the SDK\n   * derives the id from. Distinct, at most {@link MAX_LINEAGE_SOURCES}, all\n   * belonging to the same owner as the target scope, never the record's own\n   * id. Sent lowercased as the record's `lineage` field, inside the signed\n   * bytes. `[]` is an explicit root statement and is sent; absent or `null`\n   * makes no statement. Pairs also let the SDK apply the naming rule\n   * ({@link assertDerivedScopeNaming}) before anything is signed.\n   */\n  lineage?: readonly LineageSource[] | null;\n  /** `fetch` to use; defaults to `globalThis.fetch`. */\n  fetch?: typeof fetch;\n  /** Extra request headers. */\n  headers?: HeadersInit;\n  retry?: WriteTransportRetryOptions;\n}\n\n/**\n * A JSON write: `data` is stored as the record (plus `lineage` when given).\n * Anything else to store goes inside `data`; `lineage` and reserved keys are\n * not accepted in it.\n */\nexport interface WriteJsonDataParams extends WriteDataBaseParams {\n  data: Record<string, unknown>;\n  binary?: never;\n  metadata?: never;\n}\n\n/** A binary write: the bytes are stored as a `$binary` record. */\nexport interface WriteBinaryDataParams extends WriteDataBaseParams {\n  binary: WriteBinaryPayload;\n  data?: never;\n  /**\n   * Caller metadata stored with the record (`X-Vana-Metadata`, part of the\n   * signed `$binary` record). Must not contain `lineage` (use the option) or\n   * a reserved key.\n   */\n  metadata?: Record<string, unknown>;\n}\n\nexport type WriteDataParams = WriteJsonDataParams | WriteBinaryDataParams;\n\nconst WriteDataResultSchema = IngestResponseSchema.extend({\n  // Present when the write carried lineage: the validated, lowercased ids.\n  lineage: z.object({ sources: z.array(z.string()) }).optional(),\n});\n\n/** The Personal Server's ingest answer, plus the accepted lineage if any. */\nexport type WriteDataResult = IngestResponse & {\n  lineage?: { sources: Hex[] };\n};\n\nconst WriteSessionResponseSchema = z.object({\n  access_token: z.string().min(1),\n  token_type: z.string(),\n  expires_in: z.number().nonnegative(),\n  scope: z.string(),\n});\n\nfunction dataPath(scope: string): string {\n  return `/v1/data/${encodeURIComponent(scope)}`;\n}\n\n/**\n * Open a write session against a Personal Server.\n *\n * @remarks\n * Sends `POST /v1/write/session` with a Web3Signed `Authorization` header\n * whose signed claims carry `grantId`. The handshake proof is single-use on\n * the server; a transport retry signs a new one.\n *\n * @returns The session to pass to {@link writeData}.\n * @throws {WriteSessionError} When the Personal Server refuses the handshake\n *   (`errorCode` names why: `UNREGISTERED_BUILDER`, `GRANT_REQUIRED`,\n *   `GRANT_REVOKED`, `SCOPE_MISMATCH` for a grant without write entries,\n *   `INVALID_SIGNATURE` when the key is not the grantee,\n *   `GRANT_OWNER_MISMATCH`, ...).\n * @throws {WriteTransportError} When `fetch` threw on every attempt.\n * @throws {WriteRequestError} When the signer is unusable.\n */\nexport async function openWriteSession(\n  params: OpenWriteSessionParams,\n): Promise<WriteSession> {\n  const fetchFn = resolveFetch(params.fetch);\n  const personalServerUrl = normalizeBaseUrl(params.personalServerUrl);\n  const audience = params.audience ?? personalServerUrl;\n  const signer = resolveWriteSigner(params.signer, { account: params.account });\n\n  const response = await sendWithFreshProof(\n    \"Write session handshake\",\n    fetchFn,\n    params.retry,\n    proofKeyFor({\n      aud: audience,\n      method: \"POST\",\n      uri: WRITE_SESSION_PATH,\n      grantId: params.grantId,\n    }),\n    async (iat) => {\n      const headers = new Headers(params.headers);\n      headers.set(\n        \"Authorization\",\n        await buildWeb3SignedHeader({\n          signMessage: signer.signMessage,\n          aud: audience,\n          method: \"POST\",\n          uri: WRITE_SESSION_PATH,\n          grantId: params.grantId,\n          iat,\n        }),\n      );\n      return {\n        url: `${personalServerUrl}${WRITE_SESSION_PATH}`,\n        init: { method: \"POST\", headers },\n      };\n    },\n  );\n  // Read the clock before parsing so `expiresAt` never overstates the\n  // remaining lifetime.\n  const mintedAt = Date.now();\n\n  if (!response.ok) {\n    const { errorCode, message, details } =\n      await readPersonalServerErrorBody(response);\n    throw new WriteSessionError(\n      message ??\n        `Write session handshake failed: ${response.status} ${response.statusText}`,\n      response.status,\n      errorCode,\n      details,\n    );\n  }\n\n  let body: unknown;\n  try {\n    body = await response.json();\n  } catch (err) {\n    throw new WriteSessionError(\n      \"Write session response is not JSON\",\n      response.status,\n      null,\n      { cause: errorMessage(err) },\n    );\n  }\n  const parsed = WriteSessionResponseSchema.safeParse(body);\n  if (!parsed.success) {\n    throw new WriteSessionError(\n      \"Write session response is not a session\",\n      response.status,\n      null,\n      { issues: parsed.error.issues },\n    );\n  }\n  if (parsed.data.token_type.toLowerCase() !== \"bearer\") {\n    throw new WriteSessionError(\n      `Write session token type is not Bearer: ${parsed.data.token_type}`,\n      response.status,\n    );\n  }\n\n  return {\n    personalServerUrl,\n    audience,\n    grantId: params.grantId,\n    accessToken: parsed.data.access_token,\n    expiresAt: mintedAt + parsed.data.expires_in * 1000,\n    writeScopes: parsed.data.scope.split(\" \").filter((s) => s.length > 0),\n    signer,\n  };\n}\n\n/** Every field {@link writeData} relies on, checked before any is used. */\nfunction isWriteSession(value: unknown): value is WriteSession {\n  if (!isRecord(value)) return false;\n  const signer: unknown = value.signer;\n  return (\n    typeof value.personalServerUrl === \"string\" &&\n    typeof value.audience === \"string\" &&\n    typeof value.grantId === \"string\" &&\n    typeof value.accessToken === \"string\" &&\n    value.accessToken.length > 0 &&\n    typeof value.expiresAt === \"number\" &&\n    Number.isFinite(value.expiresAt) &&\n    Array.isArray(value.writeScopes) &&\n    value.writeScopes.every((scope) => typeof scope === \"string\") &&\n    isRecord(signer) &&\n    typeof signer.signMessage === \"function\"\n  );\n}\n\n/** `true` when one of the session's write patterns covers `scope`. */\nexport function sessionCoversScope(\n  session: Pick<WriteSession, \"writeScopes\">,\n  scope: string,\n): boolean {\n  if (\n    !isRecord(session) ||\n    !Array.isArray(session.writeScopes) ||\n    !session.writeScopes.every((pattern) => typeof pattern === \"string\")\n  ) {\n    throw new WriteRequestError(\"session must come from openWriteSession\");\n  }\n  return session.writeScopes.some((pattern) =>\n    scopeMatchesPattern(scope, pattern),\n  );\n}\n\n/**\n * The media type the Personal Server stores for a binary write: the\n * `Content-Type` minus its parameters, `application/octet-stream` when blank.\n */\nexport function normalizeBinaryMimeType(contentType: string | null): string {\n  if (!contentType) return \"application/octet-stream\";\n  return contentType.split(\";\")[0].trim() || \"application/octet-stream\";\n}\n\n/**\n * How the Personal Server reads an `X-Vana-Metadata` header: JSON when it\n * parses, the raw string otherwise, `undefined` when absent or blank.\n */\nexport function parseWriteMetadataHeader(value: string | null): unknown {\n  if (value === null) return undefined;\n  const trimmed = value.trim();\n  if (trimmed === \"\") return undefined;\n  try {\n    return JSON.parse(trimmed);\n  } catch {\n    return value;\n  }\n}\n\n/**\n * Encode a metadata object for the `X-Vana-Metadata` header. Non-ASCII\n * characters are `\\uXXXX`-escaped so the value is header-safe everywhere;\n * it parses back to the same object.\n */\nexport function encodeWriteMetadataHeader(\n  metadata: Record<string, unknown>,\n): string {\n  let json: string;\n  try {\n    json = JSON.stringify(metadata);\n  } catch (err) {\n    throw new WriteRequestError(\n      `metadata is not JSON-serialisable: ${errorMessage(err)}`,\n    );\n  }\n  if (typeof json !== \"string\") {\n    throw new WriteRequestError(\"metadata must serialise to JSON\");\n  }\n  return json.replace(\n    /[\\u007f-\\uffff]/g,\n    (c) => `\\\\u${c.charCodeAt(0).toString(16).padStart(4, \"0\")}`,\n  );\n}\n\nexport interface BinaryWriteSignedBytesInput {\n  /** The raw body bytes the write sends. */\n  bytes: Uint8Array;\n  /** The `Content-Type` header the write sends (parameters are ignored). */\n  contentType: string;\n  /** The `X-Filename` header value the write sends, if any. */\n  filename?: string;\n  /** The exact `X-Vana-Metadata` header value the write sends, if any. */\n  metadataHeader?: string;\n}\n\n/**\n * The bytes a builder signs for a binary write: the compact JSON of the\n * `$binary` record the Personal Server stores for these headers and bytes\n * (`personal-server-ts` `binaryWriteSignedBytes`, mirrored field for field).\n *\n * @returns UTF-8 bytes of the stored record's compact JSON.\n */\nexport function binaryWriteSignedBytes(\n  input: BinaryWriteSignedBytesInput,\n): Uint8Array {\n  const metadata = parseWriteMetadataHeader(input.metadataHeader ?? null);\n  const record: Record<string, unknown> = {\n    $binary: true,\n    mimeType: normalizeBinaryMimeType(input.contentType),\n    ...(input.filename ? { filename: input.filename } : {}),\n    sizeBytes: input.bytes.length,\n    contentHash: bytesToHex(sha256(input.bytes)),\n    encoding: \"base64\",\n    content: toBase64(input.bytes),\n    ...(metadata !== undefined ? { metadata } : {}),\n  };\n  return new TextEncoder().encode(JSON.stringify(record));\n}\n\nconst PRINTABLE_ASCII = /^[\\x20-\\x7e]*$/;\n\n/**\n * Carry a filename the way the Personal Server reads it back verbatim:\n * `X-Filename` for printable ASCII, RFC 5987 `filename*` otherwise (a raw\n * non-ASCII header value is rejected by `fetch` or mangled in transit).\n */\nfunction setFilenameHeader(headers: Headers, filename: string): void {\n  if (PRINTABLE_ASCII.test(filename)) {\n    headers.set(WRITE_FILENAME_HEADER, filename);\n    return;\n  }\n  headers.set(\n    WRITE_CONTENT_DISPOSITION_HEADER,\n    `attachment; filename*=UTF-8''${encodeURIComponent(filename)}`,\n  );\n}\n\nfunction assertNoReservedKeys(\n  value: Record<string, unknown>,\n  where: string,\n): void {\n  for (const key of RESERVED_WRITE_KEYS) {\n    if (Object.prototype.hasOwnProperty.call(value, key)) {\n      throw new WriteRequestError(\n        `${where} must not contain the reserved ${key} key; the Personal Server stamps it`,\n        { key },\n      );\n    }\n  }\n}\n\nfunction isLineagePair(\n  value: unknown,\n): value is { ownerAddress: Address; scope: string } {\n  return (\n    isRecord(value) &&\n    typeof value.ownerAddress === \"string\" &&\n    typeof value.scope === \"string\"\n  );\n}\n\n/**\n * Validate and lowercase the sources the way the Personal Server will\n * (distinct, at most {@link MAX_LINEAGE_SOURCES}, never the record's own id)\n * and apply the naming rule to every source given as a pair. `[]` is kept:\n * it is an explicit root statement.\n */\nfunction normalizeLineage(lineage: unknown, derivedScope: string): Hex[] {\n  if (!Array.isArray(lineage)) {\n    throw new WriteRequestError(\"lineage must be an array of data point ids\");\n  }\n  if (lineage.length > MAX_LINEAGE_SOURCES) {\n    throw new WriteRequestError(\n      `lineage lists ${lineage.length} sources; the maximum is ${MAX_LINEAGE_SOURCES}`,\n      { max: MAX_LINEAGE_SOURCES, count: lineage.length },\n    );\n  }\n  const seen = new Set<string>();\n  const sources: Hex[] = [];\n  const sourceScopes: string[] = [];\n  const ownIds = new Set<string>();\n  for (const entry of lineage as unknown[]) {\n    let id: Hex;\n    if (isLineagePair(entry)) {\n      if (!isAddress(entry.ownerAddress, { strict: false })) {\n        throw new WriteRequestError(\n          \"lineage source ownerAddress must be an EVM address\",\n          { ownerAddress: entry.ownerAddress },\n        );\n      }\n      if (entry.scope.length === 0) {\n        throw new WriteRequestError(\"lineage source scope is required\");\n      }\n      id = deriveDataPointId(entry.ownerAddress, entry.scope);\n      sourceScopes.push(entry.scope);\n      ownIds.add(deriveDataPointId(entry.ownerAddress, derivedScope));\n    } else if (isDataPointId(entry)) {\n      id = entry;\n    } else {\n      throw new WriteRequestError(\n        \"lineage entries must be 32-byte hex data point ids or { ownerAddress, scope } pairs\",\n        { entry },\n      );\n    }\n    const normalized = id.toLowerCase() as Hex;\n    if (seen.has(normalized)) {\n      throw new WriteRequestError(\"lineage must not repeat a data point id\", {\n        dataPointId: normalized,\n      });\n    }\n    seen.add(normalized);\n    sources.push(normalized);\n  }\n  for (const own of ownIds) {\n    if (seen.has(own)) {\n      throw new WriteRequestError(\n        \"lineage must not cite the record's own data point\",\n        { dataPointId: own, scope: derivedScope },\n      );\n    }\n  }\n  assertDerivedScopeNaming(derivedScope, sourceScopes);\n  return sources;\n}\n\nfunction assertNoLineageField(\n  value: Record<string, unknown>,\n  where: string,\n): void {\n  if (Object.prototype.hasOwnProperty.call(value, LINEAGE_FIELD)) {\n    throw new WriteRequestError(\n      `${where}.${LINEAGE_FIELD} is reserved; pass sources through the lineage option`,\n    );\n  }\n}\n\n/** The `X-Vana-Metadata` header for a binary write, or `undefined`. */\nfunction buildMetadataHeader(\n  metadata: Record<string, unknown> | undefined,\n  sources: Hex[] | undefined,\n): string | undefined {\n  if (metadata !== undefined) {\n    if (!isRecord(metadata)) {\n      throw new WriteRequestError(\"metadata must be a plain object\");\n    }\n    assertNoReservedKeys(metadata, \"metadata\");\n    assertNoLineageField(metadata, \"metadata\");\n  }\n  if (metadata === undefined && sources === undefined) return undefined;\n  return encodeWriteMetadataHeader({\n    ...(metadata ?? {}),\n    ...(sources !== undefined ? { [LINEAGE_FIELD]: sources } : {}),\n  });\n}\n\ninterface PreparedWrite {\n  body: Uint8Array;\n  /** What the proof's `bodyHash` commits to. */\n  signedBytes: Uint8Array;\n  contentType: string;\n  filename?: string;\n  metadataHeader?: string;\n}\n\nfunction prepareWrite(params: WriteDataParams): PreparedWrite {\n  if (params.binary !== undefined && params.data !== undefined) {\n    throw new WriteRequestError(\"Pass either data or binary, not both\");\n  }\n  // Absent or null lineage makes no statement: send nothing. Anything else\n  // (`[]` included: an explicit root) is validated before it is touched,\n  // since callers may be untyped.\n  const rawLineage: unknown = params.lineage;\n  const sources =\n    rawLineage === undefined || rawLineage === null\n      ? undefined\n      : normalizeLineage(rawLineage, params.scope);\n\n  if (params.binary !== undefined) {\n    const { bytes, contentType, filename } = params.binary;\n    if (!(bytes instanceof Uint8Array)) {\n      throw new WriteRequestError(\"binary.bytes must be a Uint8Array\");\n    }\n    if (typeof contentType !== \"string\" || contentType.trim() === \"\") {\n      throw new WriteRequestError(\"binary.contentType is required\");\n    }\n    if (filename !== undefined) {\n      if (typeof filename !== \"string\") {\n        throw new WriteRequestError(\"binary.filename must be a string\");\n      }\n      if (filename !== filename.trim()) {\n        throw new WriteRequestError(\n          \"binary.filename must not have leading or trailing whitespace\",\n        );\n      }\n    }\n    const metadataHeader = buildMetadataHeader(params.metadata, sources);\n    return {\n      body: bytes,\n      signedBytes: binaryWriteSignedBytes({\n        bytes,\n        contentType,\n        filename,\n        metadataHeader,\n      }),\n      contentType,\n      filename,\n      metadataHeader,\n    };\n  }\n\n  if (params.data === undefined) {\n    throw new WriteRequestError(\"Pass data (a JSON object) or binary\");\n  }\n  if (!isRecord(params.data)) {\n    throw new WriteRequestError(\"data must be a plain JSON object\");\n  }\n  if (params.metadata !== undefined) {\n    throw new WriteRequestError(\n      \"metadata applies to binary writes; put fields to store inside data\",\n    );\n  }\n  assertNoReservedKeys(params.data, \"data\");\n  assertNoLineageField(params.data, \"data\");\n  const record =\n    sources === undefined\n      ? params.data\n      : { ...params.data, [LINEAGE_FIELD]: sources };\n  let text: string;\n  try {\n    // Compact JSON is the contract: the server re-serialises the parsed\n    // record and requires it to match the signed bytes.\n    text = JSON.stringify(record);\n  } catch (err) {\n    throw new WriteRequestError(\n      `data is not JSON-serialisable: ${errorMessage(err)}`,\n    );\n  }\n  if (typeof text !== \"string\" || !text.startsWith(\"{\")) {\n    throw new WriteRequestError(\"data must serialise to a JSON object\");\n  }\n  const body = new TextEncoder().encode(text);\n  return {\n    body,\n    signedBytes: body,\n    contentType: \"application/json\",\n  };\n}\n\nasync function writeErrorFromResponse(\n  response: Response,\n): Promise<PersonalServerWriteError> {\n  const { errorCode, message, details } =\n    await readPersonalServerErrorBody(response);\n  const text =\n    message ??\n    `Personal Server write failed: ${response.status} ${response.statusText}`;\n  // Lineage rejections span 400 / 422 / 502; the code is the discriminator.\n  if (response.status === 422 || errorCode?.startsWith(\"LINEAGE_\")) {\n    return new WriteLineageError(text, response.status, errorCode, details);\n  }\n  switch (response.status) {\n    case 401:\n      return new WriteUnauthorizedError(text, errorCode, details);\n    case 403:\n      return new WriteForbiddenError(text, errorCode, details);\n    case 409:\n      return new WriteConflictError(text, errorCode, details);\n    default:\n      return new WriteRejectedError(text, response.status, errorCode, details);\n  }\n}\n\n/**\n * Write one record into a scope under an open write session.\n *\n * @remarks\n * Sends `POST /v1/data/:scope` with `Authorization: Bearer <session token>`\n * and `X-Vana-Write-Signature`, a Web3Signed proof over the stored\n * representation carrying the session's `grantId` as a signed claim. JSON\n * writes send `data` as compact JSON with `Content-Type: application/json`;\n * binary writes send the bytes with their `Content-Type`, `X-Filename`, and\n * sign {@link binaryWriteSignedBytes}. `lineage` is the record's top-level\n * `lineage` field for JSON and the `lineage` field of `X-Vana-Metadata` for\n * binary, so the proof covers it either way.\n *\n * @returns The ingest answer (`scope`, `collectedAt`, `status`, and\n *   `lineage.sources` when the write carried lineage).\n * @throws {WriteRequestError} Before sending: no payload, a reserved key, a\n *   malformed lineage id, or non-object data.\n * @throws {WriteSessionExpiredError} Before sending: the session token has\n *   passed its lifetime.\n * @throws {WriteUnauthorizedError} 401 (proof or session rejected).\n * @throws {WriteForbiddenError} 403 (grant no longer authorises the write).\n * @throws {WriteConflictError} 409.\n * @throws {WriteLineageError} Any `LINEAGE_*` rejection: 422\n *   `LINEAGE_SOURCE_UNKNOWN` (`details.unknown`), 400 `LINEAGE_INVALID` /\n *   `LINEAGE_SCOPE_UNDER_SOURCE_PREFIX`, 502 `LINEAGE_SOURCE_LOOKUP_FAILED`.\n * @throws {WriteRejectedError} Any other non-2xx.\n * @throws {WriteTransportError} `fetch` threw on every attempt.\n */\nexport async function writeData(\n  params: WriteDataParams,\n): Promise<WriteDataResult> {\n  const { session } = params;\n  if (!isWriteSession(session)) {\n    throw new WriteRequestError(\"session must come from openWriteSession\");\n  }\n  const fetchFn = resolveFetch(params.fetch);\n  if (typeof params.scope !== \"string\" || params.scope.length === 0) {\n    throw new WriteRequestError(\"scope is required\");\n  }\n  const prepared = prepareWrite(params);\n  if (Date.now() >= session.expiresAt) {\n    throw new WriteSessionExpiredError(\n      \"Write session has expired; open a new session\",\n      { grantId: session.grantId, expiresAt: session.expiresAt },\n    );\n  }\n\n  const path = dataPath(params.scope);\n  const response = await sendWithFreshProof(\n    `Write to ${params.scope}`,\n    fetchFn,\n    params.retry,\n    proofKeyFor({\n      aud: session.audience,\n      method: \"POST\",\n      uri: path,\n      grantId: session.grantId,\n      signedBytes: prepared.signedBytes,\n    }),\n    async (iat) => {\n      const headers = new Headers(params.headers);\n      headers.set(\"Content-Type\", prepared.contentType);\n      headers.set(\"Authorization\", `Bearer ${session.accessToken}`);\n      if (prepared.filename) {\n        setFilenameHeader(headers, prepared.filename);\n      }\n      if (prepared.metadataHeader !== undefined) {\n        headers.set(WRITE_METADATA_HEADER, prepared.metadataHeader);\n      }\n      headers.set(\n        WRITE_SIGNATURE_HEADER,\n        await buildWeb3SignedHeader({\n          signMessage: session.signer.signMessage,\n          aud: session.audience,\n          method: \"POST\",\n          uri: path,\n          body: prepared.signedBytes,\n          grantId: session.grantId,\n          iat,\n        }),\n      );\n      return {\n        url: `${session.personalServerUrl}${path}`,\n        init: {\n          method: \"POST\",\n          headers,\n          body: prepared.body as unknown as BodyInit,\n        },\n      };\n    },\n  );\n\n  if (!response.ok) {\n    throw await writeErrorFromResponse(response);\n  }\n  let body: unknown;\n  try {\n    body = await response.json();\n  } catch (err) {\n    throw new WriteRejectedError(\n      \"Personal Server write response is not JSON\",\n      response.status,\n      null,\n      { cause: errorMessage(err) },\n    );\n  }\n  const parsed = WriteDataResultSchema.safeParse(body);\n  if (!parsed.success) {\n    throw new WriteRejectedError(\n      \"Personal Server write response is not an ingest result\",\n      response.status,\n      null,\n      { issues: parsed.error.issues },\n    );\n  }\n  return parsed.data as WriteDataResult;\n}\n\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown\n  ? Omit<T, K>\n  : never;\n\nexport type WritePersonalServerDataParams = Omit<\n  OpenWriteSessionParams,\n  \"fetch\" | \"headers\" | \"retry\"\n> &\n  DistributiveOmit<WriteDataParams, \"session\">;\n\n/** {@link writePersonalServerData}'s answer: the ingest result plus the session it opened. */\nexport interface WritePersonalServerDataResult extends WriteDataResult {\n  /** Reuse for further writes until `expiresAt`. */\n  session: WriteSession;\n}\n\n/**\n * Open a write session and write one record in a single call.\n *\n * @remarks\n * Equivalent to {@link openWriteSession} followed by {@link writeData}. The\n * session is returned so further writes can reuse it; opening one per write\n * is correct but costs an extra signature and round-trip each time.\n *\n * @throws Everything {@link openWriteSession} and {@link writeData} throw.\n */\nexport async function writePersonalServerData(\n  params: WritePersonalServerDataParams,\n): Promise<WritePersonalServerDataResult> {\n  const session = await openWriteSession({\n    personalServerUrl: params.personalServerUrl,\n    signer: params.signer,\n    grantId: params.grantId,\n    account: params.account,\n    audience: params.audience,\n    fetch: params.fetch,\n    headers: params.headers,\n    retry: params.retry,\n  });\n  const writeParams = { ...params, session } as WriteDataParams;\n  const result = await writeData(writeParams);\n  return { ...result, session };\n}\n"],"mappings":"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","names":[]}