{"version":3,"sources":["../src/net/NodeClient.ts","../src/net/HttpClient/Headers.ts","../src/net/HttpClient.ts","../src/net/HttpClient/Body.ts","../src/net/HttpClient/Request.ts","../src/serviceDiscovery/ServiceManager.ts","../src/authentication/RemarkableTokenPayload.ts","../src/authentication/Session.ts","../src/authentication/Device.ts","../src/internal/Document.ts","../src/internal/FileBuffer.ts","../src/internal/FileBufferType.ts","../src/internal/Folder.ts","../src/internal/FileSystemSnapshot.ts","../src/internal/FileSystem.ts","../src/internal/HashUrl.ts","../src/net/FetchClient.ts","../src/RemarkableClient.ts"],"names":["https","_entries","Headers","headers","__privateAdd","__privateSet","__privateGet","HttpClient","host","path","body","requestContext","InvalidBodyPayloadError","message","_content","_serialized","_Body","content","payload","Body","_body","Request","method","NodeClient","request","resolve","reject","httpsRequest","response","responseData","chunk","error","SERVICE_DISCOVERY_HOST","REMARKABLE_API_SERVICES","ServiceManager","HttpClientConstructor","session","service","discoveryResponse","discoveryPayload","jwtDecode","REMARKABLE_JWT_MAPPING","InvalidRemarkableTokenError","RemarkableTokenPayload","_RemarkableTokenPayload","token","parsedToken","jwtKey","Session","sessionToken","sessionTokenPayload","Device","_Device","id","description","oneTimeCode","pairResponse","deviceToken","deviceTokenPayload","connectResponse","Document","hash","name","fileType","lastModified","lastOpened","folder","TextEncoder","fs","fromByteArray","UnsupportedFileExtensionError","BUFFER_TYPE_SIGNATURES","MIME_TYPE_MAPS","FileBufferType","_FileBufferType","buffer","signature","type","sig","byte","index","FileNotUploadedError","DocumentReference","FileBuffer","_FileBuffer","serviceManager","fileBuffer","uploadResponsePayload","encoder","namePayload","encodedNamePayload","Folder","parentFolder","folders","documents","_documents","_folders","FileSystemSnapshot","document","_documentPayloads","_folderPayloads","FileSystemParser","rawFileSystemPayload","folderPayload","documentPayload","f","d","subFolder","_serviceManager","_lastFetchSnapshot","FileSystem","fileSystemPayload","fileSystemParser","HashPathRequestError","HashContentRequestError","InvalidHashUrlMethodError","ExpiredHashUrlError","HashUrl","_HashUrl","rootHash","hashPathPayload","FetchClient","_HttpClientConstructor","_device","_fileSystem","_session","_RemarkableClient","httpClientConstructor","RemarkableClient"],"mappings":"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","sourcesContent":["import * as https from 'https'\nimport { type BodyPayload } from './HttpClient/Body'\nimport { type HeadersPayload } from './HttpClient/Headers'\nimport HttpClient from './HttpClient'\nimport Request from './HttpClient/Request'\n\n/**\n * { @link HttpClient } which uses Node.js `https` module to perform HTTP requests.\n */\nexport default class NodeClient extends HttpClient {\n  public static async get (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'GET', headers, null))\n  }\n\n  public static async post (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload | null = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'POST', headers, body))\n  }\n\n  public static async patch (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload | null = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'PATCH', headers, body))\n  }\n\n  public static async put (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload | null = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'PUT', headers, body))\n  }\n\n  public static async delete (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'DELETE', headers, null))\n  }\n\n  private static async makeRequest (request: Request): Promise<Response> {\n    // eslint-disable-next-line @typescript-eslint/ban-types\n    return await new Promise((resolve: Function, reject: Function) => {\n      let path = request.url.pathname\n\n      if (request.url.search != null) path += request.url.search\n\n      const httpsRequest = https.request(\n        {\n          method: request.method,\n          hostname: request.url.hostname,\n          path,\n          headers: request.headers.entries\n        },\n        (response) => {\n          let responseData: string = ''\n\n          // eslint-disable-next-line no-return-assign\n          response.on('data', (chunk): string => responseData += chunk)\n\n          response.on('end', () =>\n            resolve(new Response(responseData, { status: response.statusCode, statusText: response.statusMessage }))\n          )\n        }\n      )\n\n      httpsRequest.on('error', (error) => { reject(error) })\n\n      if (request.body != null) httpsRequest.write(request.body)\n\n      httpsRequest.end()\n    })\n  }\n\n  private static request (\n    host: string,\n    path: string,\n    method: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload = {}\n  ): Request {\n    return new Request(host, path, method, headers, body)\n  }\n}\n","export type HeadersPayload = Record<string, string>\n\n/**\n * { @link HttpClient } { @link Request } headers\n *\n * Encapsulates a collection of `http` `header` key - value pairs\n * and provides logic to export them in different formats\n * compatible with `http` libraries.\n */\nexport default class Headers {\n  /**\n   * Original HTTP request `headers` payload.\n   * @private\n   */\n  readonly #entries: Record<string, string>\n\n  constructor (headers: HeadersPayload) {\n    this.#entries = headers\n  }\n\n  get entries (): Record<string, string> {\n    return this.#entries\n  }\n}\n","import Headers, { type HeadersPayload } from './HttpClient/Headers'\nimport type Context from './HttpClient/Context'\nimport { type BodyPayload } from './HttpClient/Body'\n\n/**\n * Interface for library HTTP client.\n *\n * Provides a RESTful interface for performing HTTP requests. All http\n * requests performed by the library should be done through this interface.\n *\n * `HttpClients` interface consists on a set of static methods for performing\n * HTTP requests. To perform multiple requests with a base `host` and set of\n * `headers` use the instance methods by instantiating the client with the\n * base `host` and `headers` as context.\n */\nexport default abstract class HttpClient {\n  public static async get (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    throw new Error('HTTP Client does not implement get static method')\n  }\n\n  public static async post (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload = {}\n  ): Promise<Response> {\n    throw new Error('HTTP Client does not implement post static method')\n  }\n\n  public static async patch (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload = {}\n  ): Promise<Response> {\n    throw new Error('HTTP Client does not implement patch static method')\n  }\n\n  public static async put (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload = {}\n  ): Promise<Response> {\n    throw new Error('HTTP Client does not implement put static method')\n  }\n\n  public static async delete (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    throw new Error('HTTP Client does not implement delete static method')\n  }\n\n  readonly context: Context\n\n  constructor (host: string, headers: HeadersPayload = {}) {\n    this.context = { host, headers: new Headers(headers) }\n  }\n\n  /**\n   * Perform a GET request.\n   *\n   * @param path - Request path destination (https://{@link host}/{@link path})\n   * @param headers - Request headers. Merged with client { @link context.headers } when performing request\n   */\n  public async get (\n    path: string,\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    const requestContext = this.requestContext(headers)\n\n    return await this.classReference()\n      .get(requestContext.host, path, requestContext.headers.entries)\n  }\n\n  /**\n   * Perform a POST request.\n   *\n   * @param path - Request path destination (https://{@link host}/{@link path})\n   * @param body - Request body payload\n   * @param headers - Request headers. Merged with client { @link context.headers } when performing request\n   */\n  public async post (\n    path: string,\n    body: BodyPayload = {},\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    const requestContext = this.requestContext(headers)\n\n    return await this.classReference()\n      .post(requestContext.host, path, requestContext.headers.entries, body)\n  }\n\n  /**\n   * Perform a PATCH request.\n   *\n   * @param path - Request path destination (https://{@link host}/{@link path})\n   * @param body - Request body payload\n   * @param headers - Request headers. Merged with client { @link context.headers } when performing request\n   */\n  public async patch (\n    path: string,\n    body: BodyPayload = {},\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    const requestContext = this.requestContext(headers)\n\n    return await this.classReference()\n      .patch(requestContext.host, path, requestContext.headers.entries, body)\n  }\n\n  /**\n   * Perform a PUT request.\n   *\n   * @param path - Request path destination (https://{@link host}/{@link path})\n   * @param body - Request body payload\n   * @param headers - Request headers. Merged with client { @link context.headers } when performing request\n   */\n  public async put (\n    path: string,\n    body: BodyPayload = {},\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    const requestContext = this.requestContext(headers)\n\n    return await this.classReference()\n      .put(requestContext.host, path, requestContext.headers.entries, body)\n  }\n\n  /**\n   * Perform a DELETE request.\n   *\n   * @param path - Request path destination (https://{@link host}/{@link path})\n   * @param headers - Request headers. Merged with client { @link context.headers } when performing request\n   */\n  public async delete (\n    path: string,\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    const requestContext = this.requestContext(headers)\n\n    return await this.classReference()\n      .delete(requestContext.host, path, requestContext.headers.entries)\n  }\n\n  /**\n   * Get the underlying `HttpClient` instance class reference.\n   *\n   * Used to perform HTTP requests through the client specific http static methods.\n   *\n   * @private\n   */\n  private classReference (): typeof HttpClient {\n    return this.constructor as typeof HttpClient\n  }\n\n  /**\n   * Request specific configuration. Merges client { @link context.headers }\n   * with request specific headers.\n   *\n   * @param headers - Request specific headers\n   *\n   * @private\n   */\n  private requestContext (headers: HeadersPayload): Context {\n    return {\n      host: this.context.host,\n      headers: new Headers({ ...this.context.headers.entries, ...(new Headers(headers)).entries })\n    }\n  }\n}\n","/**\n * Error raised when HTTP request `body` type is not supported by { @link HttpClient } { @link Body }.\n *\n * { @link Body } only supports body types:\n *\n * - `ArrayBuffer`\n * - `Buffer`\n * - `String`\n * - `Record`\n */\nexport class InvalidBodyPayloadError extends Error {\n  constructor (message: string) {\n    super(message)\n    this.name = 'InvalidBodyError'\n  }\n}\n\n/**\n * HTTP request `body` types supported by { @link HttpClient } { @link Body }.\n *\n * These types can be converted into a `serialized` format, compatible with `http` libraries,\n * by the { @link HttpClient } { @link Body } to be dispatched as `body` in an\n * HTTP POST / PATCH / PUT request.\n */\nexport type BodyPayload = Record<string, string | boolean | number> | ArrayBuffer | Buffer | string\n\n/**\n * Serialized HTTP request `body`.\n *\n * These types are compatible with `http` libraries and can be dispatched as `body` in an\n * HTTP POST / PATCH / PUT request.\n */\nexport type SerializedBodyPayload = string | ArrayBuffer | Buffer\n\n/**\n * { @link HttpClient } { @link Request } body\n *\n * Serializes different data types qualified to be dispatched as `body`\n * in an HTTP request into an `http` request body compatible format.\n */\nexport default class Body {\n  /**\n   * Transforms a `body` payload into a serialized format compatible with `http` libraries.\n   *\n   * @param payload - HTTP request `body` payload, in a format supported by { @link HttpClient } { @link Body }.\n   * @returns Payload in `http` request body compatible format.\n   */\n  static serialize (payload: BodyPayload): SerializedBodyPayload {\n    switch (typeof payload) {\n      case 'object':\n        if (payload instanceof ArrayBuffer || payload instanceof Buffer) {\n          return payload\n        } else {\n          return JSON.stringify(payload)\n        }\n      case 'string':\n        return payload\n      default:\n        throw new InvalidBodyPayloadError(\n          `\n           ${(payload as unknown).constructor.name} Http body payload not supported.\n           Supported types are: ArrayBuffer, Buffer, String & Record.\n          `\n        )\n    }\n  }\n\n  /**\n   * Original HTTP request `body` payload.\n   * @private\n   */\n  readonly #content: BodyPayload\n\n  /**\n   * Serialized HTTP request `body` payload, compatible with `http` libraries.\n   * @private\n   */\n  readonly #serialized: SerializedBodyPayload\n\n  constructor (content: BodyPayload) {\n    this.#content = content\n    this.#serialized = Body.serialize(content)\n  }\n\n  get content (): BodyPayload {\n    return this.#content\n  }\n\n  get serialized (): SerializedBodyPayload {\n    return this.#serialized\n  }\n}\n","import Body, { type SerializedBodyPayload, type BodyPayload } from './Body'\nimport Headers from './Headers'\nimport { type HeadersPayload } from './Headers'\n\n/**\n * { @link HttpClient } request\n *\n * Models an HTTP request to be dispatched by { @link HttpClient }.\n *\n * Serializes `headers` and `body` information into an `http` request compatible format.\n */\nexport default class Request {\n  readonly url: URL\n  readonly method: string\n  readonly headers?: Headers = null\n  readonly #body?: Body = null\n\n  constructor (\n    host: string,\n    path: string,\n    method: string,\n    headers: HeadersPayload = null,\n    body: BodyPayload = null\n  ) {\n    this.method = method\n    this.url = new URL(path, host)\n\n    if (headers != null) this.headers = new Headers(headers)\n    if (body != null) this.#body = new Body(body)\n  }\n\n  /**\n   * Serialized HTTP request `body` payload, ready to be dispatches in an `http` request.\n   */\n  get body (): SerializedBodyPayload {\n    return this.#body?.serialized\n  }\n}\n","import NodeClient from '../net/NodeClient'\nimport type HttpClient from '../net/HttpClient'\nimport { type HeadersPayload } from '../net/HttpClient/Headers'\nimport { type Session } from '../authentication'\n\nconst SERVICE_DISCOVERY_HOST: string = 'https://service-manager-production-dot-remarkable-production.appspot.com'\n\nconst REMARKABLE_API_SERVICES: Record<string, string> = {\n  documentStorage: '/service/json/1/document-storage?environment=production&group=auth0%7C5a68dc51cb30df3877a1d7c4&apiVer=2'\n}\n\n/**\n * Response payload returned by the `/service` reMarkable API endpoint.\n */\ninterface ServiceManagerResponse {\n  Status: 'OK' | string\n  Host: string\n}\n\n/**\n * Generates `HttpClient` instances preconfigured for performing\n * requests to the different services available in the reMarkable\n * Cloud API.\n *\n * Each service in the reMarkable Cloud API (such as authentication,\n * document storage, ...) has a specific host. The `/service` API\n * endpoint allows developers to fetch the these hosts. This class\n * provides a public interface of methods representing all the\n * services available in the API.\n *\n * Use these methods to get instances of the `HttpClient` configured\n * with the corresponding host and authentication headers for the\n * service you want to make use of.\n */\nexport default class ServiceManager {\n  /**\n   * Returns `HttpClient` configured with host and header options to\n   * perform requests to the reMarkable production API.\n   *\n   * This API endpoint is not a service per-se, but provides some similar\n   * utilities other services provide (such as device pairing or session\n   * creation). To keep the logic to fetch endpoints consistent, this\n   * method encapsulates the endpoint logic as if it was another service.\n   *\n   * Some of the utilities the endpoint provide does not require from\n   * any headers. By defining this method as static, we can make use\n   * of this endpoint without requiring a `Device` instance (as it\n   * is required for other endpoints).\n   */\n  static productionHttpClient (\n    headers: HeadersPayload = {},\n    HttpClientConstructor: unknown = NodeClient\n  ): HttpClient {\n    // @ts-expect-error - httpClientConstructor is a constructor\n    return new HttpClientConstructor('https://webapp-prod.cloud.remarkable.engineering', headers)\n  }\n\n  public readonly session: Session\n  public readonly httpClient: HttpClient\n\n  constructor (session: Session, HttpClientConstructor: unknown = NodeClient) {\n    this.session = session\n\n    // @ts-expect-error - httpClientConstructor is a constructor\n    this.httpClient = new HttpClientConstructor(SERVICE_DISCOVERY_HOST, {\n      Authorization: `Bearer ${this.session.token}`\n    })\n  }\n\n  /**\n   * Returns `HttpClient` configured with host and header options to\n   * perform requests to the reMarkable Document Storage API service.\n   */\n  public async documentStorageHttpClient (): Promise<HttpClient> {\n    return await this.serviceHttpClient('documentStorage')\n  }\n\n  /**\n   * Returns `HttpClient` configured with host and header options to\n   * perform requests to the reMarkable internal API.\n   *\n   * This API endpoint is not a service per-se, but provides some similar\n   * utilities other services provide (such as file upload). To keep the\n   * logic to fetch endpoints consistent, this method encapsulates the\n   * endpoint logic as if it was another service.\n   */\n  public async internalCloudHttpClient (): Promise<HttpClient> {\n    return await new Promise((resolve, reject = () => {}) => {\n      resolve(\n        new NodeClient(\n          'https://internal.cloud.remarkable.com',\n          { Authorization: `Bearer ${this.session.token}` }\n        )\n      )\n\n      reject(new Error('Not implemented'))\n    })\n  }\n\n  private async serviceHttpClient (service: string): Promise<HttpClient> {\n    const discoveryResponse = await this.httpClient.get(REMARKABLE_API_SERVICES[service])\n\n    if (discoveryResponse.status !== 200) {\n      throw new Error(\n        `Failed to find Remarkable API ${service} Service:\n        ${discoveryResponse.statusText} - ${await discoveryResponse.text()}`\n      )\n    }\n\n    const discoveryPayload: ServiceManagerResponse = await discoveryResponse.json()\n\n    return new NodeClient(\n      `https://${discoveryPayload.Host}`,\n      { Authorization: `Bearer ${this.session.token}` }\n    )\n  }\n}\n","import { jwtDecode } from 'jwt-decode'\nimport type { DeviceDescription } from './DeviceDescription'\n\nconst REMARKABLE_JWT_MAPPING = {\n  deviceId: 'device-id',\n  deviceDescription: 'device-desc'\n}\n\nexport class InvalidRemarkableTokenError extends Error {}\n\n/**\n * reMarkable Cloud API JWT token payload for pairing & authentication requests\n */\nexport default class RemarkableTokenPayload {\n  /**\n   * Validates a reMarkable Cloud API JWT token.\n   *\n   * a reMarkable Cloud API JWT represents a `device` via its ID\n   * and description. Every reMarkable Cloud API JWT token must\n   * contain these two fields.\n   *\n   * @param token\n   */\n  static valid (token: string): boolean {\n    const parsedToken = jwtDecode(token)\n\n    return Object.values(REMARKABLE_JWT_MAPPING).every((jwtKey) => {\n      return Object.keys(parsedToken).includes(jwtKey)\n    })\n  }\n\n  public readonly token: string\n  public readonly deviceId: string\n  public readonly deviceDescription: DeviceDescription\n  public readonly tokenIssuedTimestamp: number\n  public readonly tokenExpirationTimestamp: number\n\n  constructor (token: string) {\n    const parsedToken = jwtDecode(token)\n\n    if (!RemarkableTokenPayload.valid(token)) {\n      throw new InvalidRemarkableTokenError(`\n        Invalid reMarkable Cloud API token. A valid reMarkable\n        Cloud API token contains a device ID and description.\n        The current token does contains ${Object.keys(parsedToken).join(', ')} fields.\n      `)\n    }\n\n    this.deviceId = parsedToken[REMARKABLE_JWT_MAPPING.deviceId]\n    this.deviceDescription = parsedToken[REMARKABLE_JWT_MAPPING.deviceDescription]\n\n    this.token = token\n    this.tokenIssuedTimestamp = parsedToken.iat\n    this.tokenExpirationTimestamp = parsedToken.exp\n  }\n}\n","import RemarkableTokenPayload from './RemarkableTokenPayload'\n\n/**\n * Represents a reMarkable Cloud API session.\n *\n * The reMarkable Cloud API uses JWT token based authentication. All requests\n * performed to the API (expect the authentication ones) must contain a valid\n * JWT token which identifies the (@link Device) performing the request.\n *\n * The `Session` class provides an interface to access the authentication\n * token information and verify its validity.\n */\nexport default class Session {\n  public readonly deviceId: string\n  public readonly expiresAt: Date\n  public readonly token: string\n\n  constructor (sessionToken: string) {\n    const sessionTokenPayload = new RemarkableTokenPayload(sessionToken)\n\n    this.deviceId = sessionTokenPayload.deviceId\n    this.expiresAt = new Date(sessionTokenPayload.tokenExpirationTimestamp)\n    this.token = sessionToken\n  }\n\n  get expired (): boolean {\n    return Date.now() >= this.expiresAt.getTime()\n  }\n}\n","import type HttpClient from '../net/HttpClient'\nimport { type DeviceDescription } from './DeviceDescription'\nimport ServiceManager from '../serviceDiscovery/ServiceManager'\nimport RemarkableTokenPayload from './RemarkableTokenPayload'\nimport Session from './Session'\nimport NodeClient from '../net/NodeClient'\n\n/**\n * Represents a reMarkable device. Provides an interface to\n * authenticate with the reMarkable Cloud API.\n *\n * The reMarkable Cloud API uses `devices` to authenticate users. A\n * `device` is any software paired to a reMarkable Cloud user account.\n * `devices` are represented by a `device token`. A `device token` is\n * a JWT token without expiration date. It is used to fetch `session tokens`\n * from the reMarkable Cloud API, which can be used to perform authenticated\n * request to the different API services.\n *\n * The `Device` class encapsulates the logic to pair new applications to\n * reMarkable Cloud user accounts and create user sessions for interacting\n * with the reMarkable Cloud API.\n *\n * Paired `Devices` are listed in: [https://my.remarkable.com/device/remarkable](https://my.remarkable.com/device/remarkable)\n */\nexport default class Device {\n  /**\n   * Creates a new device and pairs it to a reMarkable Cloud user account.\n   *\n   * @param id - Unique `device` ID (uuid v4)\n   * @param description - Label which indicates the `device` running environment (web browser, mobile app, ...)\n   * @param oneTimeCode - One-time password to authenticate reMarkable Cloud user account when pairing `device`\n   * @param HttpClientConstructor - HttpClient used for generating pair token\n   */\n  public static async pair (\n    id: string,\n    description: DeviceDescription,\n    oneTimeCode: string,\n    HttpClientConstructor: unknown = NodeClient\n  ): Promise<Device> {\n    const httpClient = ServiceManager.productionHttpClient({}, HttpClientConstructor)\n\n    const pairResponse = await httpClient.post(\n      '/token/json/2/device/new',\n      {\n        code: oneTimeCode,\n        deviceID: id,\n        deviceDesc: description\n      }\n    )\n\n    if (pairResponse.status !== 200) {\n      throw new Error(`Failed to pair with Remarkable API: ${pairResponse.statusText}`)\n    }\n\n    return new Device(await pairResponse.text())\n  }\n\n  /**\n   * `device` unique identifier (uuid v4)\n   */\n  public readonly id: string\n  /**\n   * `device` running environment (web browser, mobile app, ...)\n   */\n  public readonly description: DeviceDescription\n  /**\n   * reMarkable Cloud API token associated to `device`\n   */\n  public readonly token: string\n\n  private readonly httpClient: HttpClient\n\n  constructor (deviceToken: string, HttpClientConstructor: unknown = NodeClient) {\n    const deviceTokenPayload = new RemarkableTokenPayload(deviceToken)\n\n    this.id = deviceTokenPayload.deviceId\n    this.description = deviceTokenPayload.deviceDescription\n    this.token = deviceToken\n\n    this.httpClient = ServiceManager.productionHttpClient(\n      { Authorization: `Bearer ${this.token}` },\n      HttpClientConstructor\n    )\n  }\n\n  /**\n   * Creates a new `device` `session`.\n   *\n   * Fetches a new session token from the reMarkable Cloud API. This token\n   * can be used to perform authenticated requests to the reMarkable Cloud API\n   * in behalf of the user account associated to the `device`.\n   */\n  public async connect (): Promise<Session> {\n    const connectResponse = await this.httpClient.post('/token/json/2/user/new', {})\n\n    if (connectResponse.status !== 200) {\n      throw new Error(`Failed to connect with Remarkable API: ${await connectResponse.text()}`)\n    }\n\n    return new Session(await connectResponse.text())\n  }\n}\n","import type Folder from './Folder'\n\n/**\n * Represents a reMarkable Cloud document\n */\nexport default class Document {\n  id: string\n  hash: string\n  name: string\n  fileType: 'pdf' | 'epub' | 'notebook'\n  folder?: Folder\n  lastModified: Date\n  lastOpened: Date\n\n  constructor (\n    id: string,\n    hash: string,\n    name: string,\n    fileType: 'pdf' | 'epub' | 'notebook',\n    lastModified?: Date,\n    lastOpened?: Date,\n    folder?: Folder\n  ) {\n    this.id = id\n    this.hash = hash\n    this.name = name\n    this.fileType = fileType\n    this.lastModified = lastModified\n    this.lastOpened = lastOpened\n    this.folder = folder\n  }\n}\n","import { TextEncoder } from '@polkadot/x-textencoder'\nimport { promises as fs } from 'fs'\nimport { fromByteArray } from 'base64-js'\n\nimport FileBufferType from './FileBufferType'\nimport type HttpClient from '../net/HttpClient'\nimport type ServiceManager from '../serviceDiscovery/ServiceManager'\n\nexport class FileNotUploadedError extends Error {}\n\n/**\n * Response payload returned by reMarkable Cloud after uploading a file\n */\nexport interface UploadResponsePayload {\n  docID: string\n  hash: string\n}\n\n/**\n * Represents a reference to an uploaded { @link Document }\n *\n * In the reMarkable Cloud API, documents are identified by a unique\n * ID and Hash. While the ID is always the same, the hash changes\n * conforming changes are pushed to the user account file system.\n *\n * The { @link DocumentReference } class parses the reMarkable Cloud\n * API success upload response and returns a reference to the uploaded\n * document.\n */\nexport class DocumentReference {\n  public readonly id: string\n  public readonly hash: string\n\n  constructor (id: string, hash: string) {\n    this.id = id\n    this.hash = hash\n  }\n}\n\n/**\n * Represents a file content, encoded as a buffer, ready to be uploaded\n * to reMarkable Cloud.\n *\n * Encapsulates the logic to handle file upload. Given the Buffer\n * content of a file, it verifies the type compatibility with the\n * reMarkable Cloud API and provides an interface to upload the file\n * and get a reference to its cloud equivalent when successfully\n * pushed.\n */\nexport default class FileBuffer {\n  /**\n   * Creates a FileBuffer from a local file\n   *\n   * Used to easily upload local files to reMarkable cloud\n   *\n   * @param {string} path\n   * @param {ServiceManager} serviceManager\n   */\n  static async fromLocalFile (path: string, serviceManager: ServiceManager): Promise<FileBuffer> {\n    const name = path.split('/').pop()\n    const buffer = await fs.readFile(path)\n\n    return new FileBuffer(name, buffer, serviceManager)\n  }\n\n  /**\n   * Creates FileBuffer from file Buffer and uploads it\n   *\n   * @param name - File name\n   * @param buffer - File content\n   * @param serviceManager\n   */\n  static async upload (name: string, buffer: Buffer, serviceManager: ServiceManager): Promise<FileBuffer> {\n    const fileBuffer = new FileBuffer(name, buffer, serviceManager)\n    await fileBuffer.upload()\n    return fileBuffer\n  }\n\n  public readonly name: string\n  public readonly buffer: Buffer\n  public readonly type: FileBufferType\n  public documentReference?: DocumentReference\n\n  private httpClient?: HttpClient\n  private readonly serviceManager: ServiceManager\n\n  constructor (name: string, buffer: Buffer, serviceManager: ServiceManager) {\n    this.name = name\n    this.buffer = buffer\n    this.serviceManager = serviceManager\n\n    this.type = new FileBufferType(buffer)\n  }\n\n  get uploaded (): boolean {\n    return this.documentReference != null\n  }\n\n  async upload (): Promise<DocumentReference> {\n    const httpClient = await this.internalCloudHttpClient()\n\n    const response = await httpClient.post(\n      '/doc/v2/files',\n      this.buffer,\n      {\n        'content-type': this.type.mimeType,\n        'rm-meta': this.encodedName,\n        'rm-source': 'RoR-Browser'\n      }\n    )\n\n    if (response.status !== 201) {\n      throw new FileNotUploadedError(`Failed to upload file to reMarkable Cloud: ${await response.text()}`)\n    }\n\n    const uploadResponsePayload = await response.json() as UploadResponsePayload\n\n    this.documentReference = new DocumentReference(uploadResponsePayload.docID, uploadResponsePayload.hash)\n\n    return this.documentReference\n  }\n\n  private async internalCloudHttpClient (): Promise<HttpClient> {\n    this.httpClient ||= await this.serviceManager.internalCloudHttpClient()\n    return this.httpClient\n  }\n\n  private get encodedName (): string {\n    const encoder = new TextEncoder()\n    const namePayload = JSON.stringify({ file_name: this.name })\n    const encodedNamePayload = encoder.encode(namePayload)\n    return fromByteArray(encodedNamePayload)\n  }\n}\n","/**\n * The reMarkable API only works with `.pdf` and `.epub` files. This error is\n * raised when an `Buffer` with an unsupported file extension is passed to\n * the `FileBufferType` class.\n */\nexport class UnsupportedFileExtensionError extends Error {}\n\n/**\n * Each `Buffer` presents a specific signature representing its corresponding\n * file type at the beginning. This constants list the signature for each one of\n * the supported file types.\n */\nconst BUFFER_TYPE_SIGNATURES = {\n  pdf: [0x25, 0x50, 0x44, 0x46],\n  epub: [0x50, 0x4b, 0x03, 0x04]\n}\n\n/**\n * Maps each file type to its corresponding MIME type.\n */\nconst MIME_TYPE_MAPS = {\n  pdf: 'application/pdf',\n  epub: 'application/epub+zip'\n}\n\n/**\n * Represents the type of the file associated to its buffer.\n *\n * It is possible to identify the type of a file by examining its buffer.\n * This class encapsulates the logic to infer a files type from its\n * respective buffer.\n *\n * Since the reMarkable Cloud API only allows uploading `.pdf` and `.epub`\n * files, the class only handles buffers with that extension, raising an\n * { @link UnsupportedFileExtensionError } when a buffer from an unsupported\n * file extension is passed.\n */\nexport default class FileBufferType {\n  static extension (buffer: Buffer): 'pdf' | 'epub' {\n    const signature = (new Uint8Array(buffer)).slice(0, 4)\n\n    for (const [type, sig] of Object.entries(BUFFER_TYPE_SIGNATURES)) {\n      if (signature.every((byte, index) => byte === sig[index])) {\n        return type as 'pdf' | 'epub'\n      }\n    }\n\n    throw new UnsupportedFileExtensionError('Unsupported file extension. Only .pdf and .epub files are supported.')\n  }\n\n  static mimeType (buffer: Buffer): string {\n    const type = this.extension(buffer)\n    return MIME_TYPE_MAPS[type]\n  }\n\n  /**\n   * Buffer file extension\n   */\n  readonly extension: string\n  /**\n   * MIME type of the buffer file\n   */\n  readonly mimeType: string\n\n  constructor (buffer: Buffer) {\n    this.extension = FileBufferType.extension(buffer)\n    this.mimeType = FileBufferType.mimeType(buffer)\n  }\n}\n","import type Document from './Document'\n\n/**\n * Represents a reMarkable Cloud folder\n */\nexport default class Folder {\n  id: string\n  hash: string\n  name: string\n  folders?: Folder[] = []\n  documents?: Document[] = []\n  parentFolder?: Folder\n  lastModified?: Date\n\n  constructor (id: string, hash: string, name: string, lastModified: Date, parentFolder?: Folder, folders?: Folder[], documents?: Document[]) {\n    this.id = id\n    this.hash = hash\n    this.name = name\n    this.lastModified = lastModified\n    this.parentFolder = parentFolder\n    this.folders = folders\n    this.documents = documents\n  }\n\n  get root (): boolean {\n    return !this.parentFolder\n  }\n}\n","import type Document from './Document'\nimport type Folder from './Folder'\n\n/**\n * Represents a snapshot of the reMarkable Cloud API file system.\n *\n * Provides a list of all { @link Document }s and { @link Folder }s in\n * the user's reMarkable Cloud account in a specific point in time.\n *\n * A snapshot is valid as long as the user does not perform any write\n * operations on the reMarkable Cloud file system. As soon a file in\n * the system is uploaded or modified, all the files hashes are modify,\n * causing the snapshot to be de-synchornized with the actual reMarkable\n * Cloud file system.\n *\n * You can see the snapshot as a cache of the reMarkable Cloud file system.\n */\nexport default class FileSystemSnapshot {\n  /**\n   * List of all {@link Document}s in user reMarkable Cloud account\n   */\n  readonly #documents: Document[]\n  /**\n   * List of all {@link Folder}s in user reMarkable Cloud account\n   */\n  readonly #folders: Folder[]\n\n  constructor (documents: Document[], folders: Folder[]) {\n    this.#documents = documents\n    this.#folders = folders\n  }\n\n  get documents (): Document[] {\n    return this.#documents\n  }\n\n  get folders (): Folder[] {\n    return this.#folders\n  }\n\n  get rootFolder (): Folder {\n    return this.#folders.find((folder) => folder.parentFolder == null)\n  }\n\n  document (id: string): Document | undefined {\n    return this.#documents.find((document) => document.id === id)\n  }\n\n  folder (id: string): Folder | undefined {\n    return this.#folders.find((folder) => folder.id === id)\n  }\n}\n","import Document from './Document'\nimport Folder from './Folder'\nimport type HttpClient from '../net/HttpClient'\nimport type ServiceManager from '../serviceDiscovery/ServiceManager'\nimport FileSystemSnapshot from './FileSystemSnapshot'\n\n/**\n * reMarkable Cloud API {@link Document} payload\n *\n * Payload returned by API when requesting documents to `/doc/v2/files` endpoint\n */\nexport interface DocumentPayload {\n  hash: string\n  id: string\n  type: 'DocumentType'\n  fileType: 'pdf' | 'epub' | 'notebook'\n  visibleName: string\n  lastModified?: string\n  lastOpened?: string\n  parent?: string\n  pinned: boolean\n}\n\n/**\n * reMarkable Cloud API {@link Folder} payload\n *\n * Payload returned by API when requesting folders to `/doc/v2/files` endpoint\n */\nexport interface FolderPayload {\n  id: string\n  hash: string\n  type: 'CollectionType'\n  visibleName: string\n  lastModified?: string\n  parent?: string\n  pinned: boolean\n}\n\n/**\n * Parses reMarkable Cloud API file system payload\n *\n * Maps the response payload from the API `/doc/v2/files` endpoint to a\n * set of {@link Document} and {@link Folder} instances. Recreates the\n * file system tree hierarchy, assigning to each {@link Document} and\n * folder its parent {@link Folder}.\n */\nexport class FileSystemParser {\n  readonly #documentPayloads: DocumentPayload[]\n  readonly #folderPayloads: FolderPayload[]\n  readonly #documents: Document[]\n  readonly #folders: Folder[]\n\n  constructor (rawFileSystemPayload: Array<DocumentPayload | FolderPayload>) {\n    this.#documentPayloads = rawFileSystemPayload.filter((payload) => payload.type === 'DocumentType') as DocumentPayload[]\n    this.#folderPayloads = rawFileSystemPayload.filter((payload) => payload.type === 'CollectionType') as FolderPayload[]\n\n    this.#folders = this.#folderPayloads.map((folderPayload) => {\n      return new Folder(\n        folderPayload.id,\n        folderPayload.hash,\n        folderPayload.visibleName,\n        (folderPayload.lastModified != null) ? new Date(folderPayload.lastModified) : null,\n        undefined,\n        [],\n        []\n      )\n    })\n\n    this.#documents = this.#documentPayloads.map((documentPayload) => {\n      return new Document(\n        documentPayload.id,\n        documentPayload.hash,\n        documentPayload.visibleName,\n        documentPayload.fileType,\n        (documentPayload.lastModified != null) ? new Date(documentPayload.lastModified) : null,\n        (documentPayload.lastOpened != null) ? new Date(documentPayload.lastOpened) : null,\n        null\n      )\n    })\n\n    this.buildFileTreeHierarchy()\n  }\n\n  get documents (): Document[] {\n    return this.#documents\n  }\n\n  get folders (): Folder[] {\n    return this.#folders\n  }\n\n  private buildFileTreeHierarchy (): void {\n    this.#folderPayloads.forEach((folderPayload) => {\n      const folder = this.folders.find((f) => f.id === folderPayload.id)\n\n      if (folderPayload.parent != null && folder.parentFolder == null) {\n        folder.parentFolder = this.folders.find((f) => f.id === folderPayload.parent)\n      }\n\n      const folderDocumentPayloads = this.#documentPayloads.filter((documentPayload) => documentPayload.parent === folder.id)\n      const folderDocuments = folderDocumentPayloads.map((documentPayload) => this.documents.find((d) => d.id === documentPayload.id))\n\n      folderDocuments.forEach((document) => {\n        document.folder = folder\n        folder.documents.push(document)\n      })\n\n      const folderFolderPayloads = this.#folderPayloads.filter((folderPayload) => folderPayload.parent === folder.id)\n      const folderFolders = folderFolderPayloads.map((folderPayload) => this.folders.find((f) => f.id === folderPayload.id))\n\n      folderFolders.forEach((subFolder) => {\n        subFolder.parentFolder = folder\n        folder.folders.push(subFolder)\n      })\n    })\n  }\n}\n\n/**\n * Represents the reMarkable Cloud API file system. Provides an\n * interface to retrieve the list of {@link Document}s and {@link Folder}s\n * in a user reMarkable Cloud account and navigate through them.\n *\n * The reMarkable API `/doc/v2/files` endpoint returns a list of all files\n * in a user reMarkable Cloud account with their respective metadata.\n *\n * The `FileSystem` class parses the API response and maps the file system\n * hierarchy to a set of {@link Document} and {@link Folder} instances,\n * providing a virtual recreation of the actual file system tree, which\n * can be then used to navigate through it in the similar way as in any\n * other file system.\n */\nexport default class FileSystem {\n  readonly #serviceManager: ServiceManager\n\n  #lastFetchSnapshot?: FileSystemSnapshot = null\n\n  constructor (serviceManager: ServiceManager) {\n    this.#serviceManager = serviceManager\n  }\n\n  get lastFetchSnapshot (): FileSystemSnapshot | undefined {\n    return this.#lastFetchSnapshot\n  }\n\n  /**\n   * Requests new reMarkable Cloud snapshot of all documents and folders in user account.\n   */\n  async snapshot (): Promise<FileSystemSnapshot> {\n    this.#lastFetchSnapshot = await this.fetchSnapshot()\n    return this.#lastFetchSnapshot\n  }\n\n  /**\n   * Requests new reMarkable Cloud list of all documents in user account.\n   *\n   * Consider using {@link snapshot} method to get a snapshot of the entire file system\n   * and fetch the documents from there instead of calling this method. Each document\n   * request triggers a fetch call of the whole file system and the post-processing\n   * of the response to build the file system tree. This is an expensive operation\n   * that should be only invoked when changes have been made to the file system\n   * (files uploaded, updated, deleted, etc).\n   *\n   * If no changes were uploaded to the reMarkable Cloud you should use the {@link snapshot}\n   * method to get the list of documents and folders in the user account. The snapshot works\n   * as a cache, and contains the file system information of the last request made to the\n   * reMarkable Cloud API.\n   */\n  async document (id: string): Promise<Document | undefined> {\n    const snapshot = await this.snapshot()\n    return snapshot.documents.find((document) => document.id === id)\n  }\n\n  /**\n   * Requests new reMarkable Cloud list of all folder in user account.\n   *\n   * Consider using {@link snapshot} method to get a snapshot of the entire file system\n   * and fetch the folder from there instead of calling this method. Each folder\n   * request triggers a fetch call of the whole file system and the post-processing\n   * of the response to build the file system tree. This is an expensive operation\n   * that should be only invoked when changes have been made to the file system\n   * (files uploaded, updated, deleted, etc).\n   *\n   * If no changes were uploaded to the reMarkable Cloud you should use the {@link snapshot}\n   * method to get the list of documents and folders in the user account. The snapshot works\n   * as a cache, and contains the file system information of the last request made to the\n   * reMarkable Cloud API.\n   */\n  async folder (id: string): Promise<Folder | undefined> {\n    const snapshot = await this.snapshot()\n    return snapshot.folders.find((folder) => folder.id === id)\n  }\n\n  private async fetchSnapshot (): Promise<FileSystemSnapshot> {\n    const httpClient: HttpClient = await this.#serviceManager.internalCloudHttpClient()\n\n    const response = await httpClient.get(\n      '/doc/v2/files',\n      { 'rm-source': 'RoR-Browser' }\n    )\n\n    if (response.status !== 200) {\n      throw new Error(`Error during file system initialization: ${await response.text()}`)\n    }\n\n    const fileSystemPayload = JSON.parse(await response.text()) as Array<DocumentPayload | FolderPayload>\n    const fileSystemParser = new FileSystemParser(fileSystemPayload)\n\n    return new FileSystemSnapshot(fileSystemParser.documents, fileSystemParser.folders)\n  }\n}\n","import type HttpClient from '../net/HttpClient'\nimport type ServiceManager from '../serviceDiscovery/ServiceManager'\nimport NodeClient from '../net/NodeClient'\n\n/**\n * Error thrown when request to fetch `hash` download URL fails.\n */\nexport class HashPathRequestError extends Error {}\n\n/**\n * Error thrown when request to fetch `hash` content fails.\n */\nexport class HashContentRequestError extends Error {}\n\n/**\n * Error thrown when `hash` download URL method is not supported.\n */\nexport class InvalidHashUrlMethodError extends Error {}\n\n/**\n * Error thrown when `hash` download URL has expired.\n */\nexport class ExpiredHashUrlError extends Error {}\n\n/**\n * reMarkable API `/downloads` endpoint response payload\n *\n * Represents the URL to access the content of a `hash`.\n *\n * Download URLs are signed. The `hash` content is accessible\n * through an HTTP request to its `url` with the `method` specified\n * (no authentication required).\n *\n * Once the `expires` date is reached, the URL is no longer valid.\n */\nexport interface HashPathPayload {\n  expires: string\n  method: 'GET' | 'PUT' | 'PATCH'\n  relative_path: string\n  url: string\n}\n\n/**\n * Represents the URL to access the content of a `hash`.\n *\n * A `hash` is a string which uniquely identifies a piece of information in the\n * reMarkable cloud. A piece of information can be a `Document`, a `Folder`,\n * metadata associated to a `Document` or a `Folder`, etc.\n *\n * To access the content of a `hash`, the reMarkable API provides a `/downloads`\n * endpoint. This endpoint returns the download URL for a given `hash`. Download\n * URLs are signed URLs with an expiration date. When performing an HTTP request\n * to the download URL, the content of the `hash` is returned. Once the expiration\n * date is reached, the URL is no longer valid, requiring a new request to the\n * `/downloads` endpoint to get a new download URL.\n *\n * The `HashUrl` class provides an interface to download the content of a `hash`.\n */\nexport default class HashUrl {\n  /**\n   * Returns `HashUrl` for a given `hash`.\n   *\n   * @param {string} hash\n   * @param {ServiceManager} serviceManager\n   */\n  static async fromHash (hash: string, serviceManager: ServiceManager): Promise<HashUrl> {\n    const httpClient: HttpClient = await serviceManager.internalCloudHttpClient()\n\n    const response = await httpClient.post(\n      '/sync/v2/signed-urls/downloads',\n      { http_method: 'GET', relative_path: hash }\n    )\n\n    if (response.status !== 200) {\n      throw new HashPathRequestError(`Error during hash ${hash} download URL request: ${await response.text()}`)\n    }\n\n    return new HashUrl(await response.json() as HashPathPayload)\n  }\n\n  /**\n   * Returns `HashUrl` for the `hash` associated to the root folder.\n   *\n   * The root folder represents the root path of the reMarkable cloud storage.\n   *\n   * @param {ServiceManager} serviceManager\n   */\n  static async fromRootHash (serviceManager: ServiceManager): Promise<HashUrl> {\n    // Fetch the `hash` string associated to the `root` folder\n    const urlForRootHash = await this.fromHash('root', serviceManager)\n    const rootHashResponse = await urlForRootHash.fetch()\n    const rootHash = await rootHashResponse.text()\n\n    // And then extract the `HashUrl` from the actual root `hash`\n    return await this.fromHash(rootHash, serviceManager)\n  }\n\n  expires: Date\n  method: 'GET' | 'PUT' | 'PATCH'\n  relativePath: string\n  url: URL\n\n  constructor (hashPathPayload: HashPathPayload) {\n    this.expires = new Date(Date.parse(hashPathPayload.expires))\n    this.method = hashPathPayload.method\n    this.relativePath = hashPathPayload.relative_path\n    this.url = new URL(hashPathPayload.url)\n  }\n\n  get expired (): boolean {\n    return this.expires.getTime() < (new Date()).getTime()\n  }\n\n  async fetch (): Promise<Response> {\n    if (this.expired) throw new ExpiredHashUrlError(`Error during hashUrl ${this.relativePath} content download request: link has expired`)\n\n    let response = null\n\n    switch (this.method) {\n      case 'GET':\n        response = await NodeClient.get(this.url.href, this.url.pathname + this.url.search)\n        break\n      default:\n        throw new InvalidHashUrlMethodError(`Error during hashUrl ${this.relativePath} content download request: method ${this.method} not supported`)\n    }\n\n    if (response.status !== 200) {\n      throw new HashContentRequestError(`Error during hashUrl ${this.relativePath} content download request: ${await response.text()}`)\n    }\n\n    return response\n  }\n}\n","import { type BodyPayload } from './HttpClient/Body'\nimport { type HeadersPayload } from './HttpClient/Headers'\nimport HttpClient from './HttpClient'\nimport Request from './HttpClient/Request'\n\n/**\n * { @link HttpClient } which uses web browser `fetch` method to perform HTTP requests.\n */\nexport default class FetchClient extends HttpClient {\n  public static async get (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'GET', headers, null))\n  }\n\n  public static async post (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload | null = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'POST', headers, body))\n  }\n\n  public static async patch (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload | null = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'PATCH', headers, body))\n  }\n\n  public static async put (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload | null = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'PUT', headers, body))\n  }\n\n  public static async delete (\n    host: string,\n    path: string,\n    headers: HeadersPayload = {}\n  ): Promise<Response> {\n    return await this.makeRequest(this.request(host, path, 'DELETE', headers, null))\n  }\n\n  private static async makeRequest (request: Request): Promise<Response> {\n    // eslint-disable-next-line @typescript-eslint/ban-types,@typescript-eslint/no-misused-promises,no-async-promise-executor\n    return await new Promise(async (resolve: Function, reject: Function) => {\n      const response = await fetch(request.url.toString(), {\n        method: request.method,\n        headers: request.headers.entries,\n        body: request.body\n      })\n\n      const responseData = await response.text()\n\n      if (response.ok) {\n        resolve(new Response(responseData, { status: response.status, statusText: response.statusText }))\n      } else {\n        reject(new Error(`HTTP error: ${response.status} - ${responseData}`))\n      }\n    })\n  }\n\n  private static request (\n    host: string,\n    path: string,\n    method: string,\n    headers: HeadersPayload = {},\n    body: BodyPayload = {}\n  ): Request {\n    return new Request(host, path, method, headers, body)\n  }\n}\n","import { Device, type DeviceDescription, Session } from './authentication'\nimport { type Folder, type Document } from './internal'\nimport FileBuffer, { type DocumentReference } from './internal/FileBuffer'\nimport FileSystem from './internal/FileSystem'\nimport FetchClient from './net/FetchClient'\nimport NodeClient from './net/NodeClient'\nimport ServiceManager from './serviceDiscovery/ServiceManager'\n\n/**\n * reMarkable Cloud API client.\n *\n * Provides an interface to interact with the reMarkable Cloud API:\n * - Navigate through the file system\n * - Upload documents\n */\nexport default class RemarkableClient {\n  static withFetchHttpClient (deviceToken?: string, sessionToken?: string): RemarkableClient {\n    return new RemarkableClient(deviceToken, sessionToken, FetchClient)\n  }\n\n  static withNodeHttpClient (deviceToken?: string, sessionToken?: string): RemarkableClient {\n    return new RemarkableClient(deviceToken, sessionToken, NodeClient)\n  }\n\n  readonly #HttpClientConstructor: unknown\n\n  #device: Device\n  #fileSystem: FileSystem\n  #serviceManager: ServiceManager\n  #session: Session\n\n  constructor (deviceToken?: string, sessionToken?: string, httpClientConstructor: unknown = NodeClient) {\n    if (deviceToken != null) {\n      this.#device = new Device(deviceToken)\n\n      if (sessionToken != null) {\n        this.#session = new Session(sessionToken)\n        this.#serviceManager = new ServiceManager(this.session, httpClientConstructor)\n        this.#fileSystem = new FileSystem(this.#serviceManager)\n      }\n    } else {\n      this.#HttpClientConstructor = httpClientConstructor\n    }\n  }\n\n  get device (): Device {\n    return this.#device\n  }\n\n  get session (): Session {\n    return this.#session\n  }\n\n  async pair (id: string, description: DeviceDescription, oneTimeCode: string): Promise<boolean> {\n    if (!this.paired) {\n      this.#device = await Device.pair(\n        id,\n        description,\n        oneTimeCode,\n        this.#HttpClientConstructor\n      )\n    }\n\n    return this.paired\n  }\n\n  async connect (): Promise<void> {\n    if (this.sessionExpired) {\n      this.#session = await this.device.connect()\n      this.#serviceManager = new ServiceManager(this.session)\n      this.#fileSystem = new FileSystem(this.#serviceManager)\n    }\n  }\n\n  async document (id: string): Promise<Document | undefined> {\n    return await this.#fileSystem.document(id)\n  }\n\n  async folder (id: string): Promise<Folder | undefined> {\n    return await this.#fileSystem.folder(id)\n  }\n\n  async upload (name: string, buffer: Buffer): Promise<DocumentReference> {\n    const fileBuffer = new FileBuffer(name, buffer, this.#serviceManager)\n    return await fileBuffer.upload()\n  }\n\n  get sessionExpired (): boolean {\n    return this.session == null || this.session.expired\n  }\n\n  get paired (): boolean {\n    return this.device != null\n  }\n}\n"]}