{"version":3,"file":"SolidLeaf.mjs","names":[],"sources":["../../src/resources/SolidLeaf.ts"],"sourcesContent":["import type { DatasetChanges } from \"@ldo/rdf-utils\";\nimport type { Quad } from \"@rdfjs/types\";\nimport { LeafBatchedRequester } from \"../requester/LeafBatchedRequester\";\nimport type { CheckRootResultError } from \"../requester/requests/checkRootContainer\";\nimport type {\n  LeafCreateAndOverwriteResult,\n  LeafCreateIfAbsentResult,\n} from \"../requester/requests/createDataResource\";\nimport type { DeleteResult } from \"../requester/requests/deleteResource\";\nimport type { ReadLeafResult } from \"../requester/requests/readResource\";\nimport type { UpdateResult } from \"../requester/requests/updateDataResource\";\nimport type { DeleteSuccess } from \"../requester/results/success/DeleteSuccess\";\nimport { DataReadSuccess } from \"../requester/results/success/SolidReadSuccess\";\nimport { BinaryReadSuccess } from \"../requester/results/success/SolidReadSuccess\";\nimport { getParentUri } from \"../util/rdfUtils\";\nimport type { NoRootContainerError } from \"../requester/results/error/NoRootContainerError\";\nimport type { SharedStatuses } from \"./SolidResource\";\nimport { SolidResource } from \"./SolidResource\";\nimport type { SolidLeafUri } from \"../types\";\nimport type { ResourceSuccess } from \"@ldo/connected\";\nimport {\n  AbsentReadSuccess,\n  Unfetched,\n  type ConnectedContext,\n} from \"@ldo/connected\";\nimport type { SolidConnectedPlugin } from \"../SolidConnectedPlugin\";\nimport type { SolidContainer } from \"./SolidContainer\";\n\n/**\n * Represents the current status of a specific Leaf on a Pod as known by LDO.\n *\n * @example\n * ```typescript\n * const leaf = solidLdoDataset\n *   .getResource(\"https://example.com/container/resource.ttl\");\n * ```\n */\nexport class SolidLeaf extends SolidResource {\n  /**\n   * The URI of the leaf\n   */\n  readonly uri: SolidLeafUri;\n\n  /**\n   * @internal\n   * Batched Requester for the Leaf\n   */\n  protected requester: LeafBatchedRequester;\n\n  /**\n   * Indicates that this resource is a leaf resource\n   */\n  readonly type = \"SolidLeaf\" as const;\n\n  /**\n   * Indicates that this resource is not an error\n   */\n  readonly isError = false as const;\n\n  /**\n   * The status of the last request made for this leaf\n   */\n  status:\n    | SharedStatuses<SolidLeaf>\n    | ReadLeafResult\n    | LeafCreateAndOverwriteResult\n    | LeafCreateIfAbsentResult\n    | UpdateResult<SolidLeaf>;\n\n  /**\n   * @internal\n   * The raw binary data if this leaf is a Binary resource\n   */\n  protected binaryData: { blob: Blob; mimeType: string } | undefined;\n\n  /**\n   * @param uri - The uri of the leaf\n   * @param context - SolidLdoDatasetContext for the parent dataset\n   */\n  constructor(\n    uri: SolidLeafUri,\n    context: ConnectedContext<SolidConnectedPlugin[]>,\n  ) {\n    super(context);\n    const uriObject = new URL(uri);\n    uriObject.hash = \"\";\n    this.uri = uriObject.toString() as SolidLeafUri;\n    this.requester = new LeafBatchedRequester(this, context);\n    this.status = new Unfetched(this);\n  }\n\n  /**\n   * ===========================================================================\n   * GETTERS\n   * ===========================================================================\n   */\n\n  /**\n   * Checks to see if the resource is currently uploading data\n   * @returns true if the current resource is uploading\n   *\n   * @example\n   * ```typescript\n   * leaf.uploadAndOverwrite(new Blob(\"some text\"), \"text/txt\").then(() => {\n   *   // Logs \"false\"\n   *   console.log(leaf.isUploading())\n   * });\n   * // Logs \"true\"\n   * console.log(leaf.isUploading());\n   * ```\n   */\n  isUploading(): boolean {\n    return this.requester.isUploading();\n  }\n\n  /**\n   * Checks to see if the resource is currently updating data\n   * @returns true if the current resource is updating\n   *\n   * @example\n   * ```typescript\n   * leaf.update(datasetChanges).then(() => {\n   *   // Logs \"false\"\n   *   console.log(leaf.isUpdating())\n   * });\n   * // Logs \"true\"\n   * console.log(leaf.isUpdating());\n   * ```\n   */\n  isUpdating(): boolean {\n    return this.requester.isUpdating();\n  }\n\n  /**\n   * If this resource is a binary resource, returns the mime type\n   * @returns The mime type if this resource is a binary resource, undefined\n   * otherwise\n   *\n   * @example\n   * ```typescript\n   * // Logs \"text/txt\"\n   * console.log(leaf.getMimeType());\n   * ```\n   */\n  getMimeType(): string | undefined {\n    return this.binaryData?.mimeType;\n  }\n\n  /**\n   * If this resource is a binary resource, returns the Blob\n   * @returns The Blob  if this resource is a binary resource, undefined\n   * otherwise\n   *\n   * @example\n   * ```typescript\n   * // Logs \"some text.\"\n   * console.log(leaf.getBlob()?.toString());\n   * ```\n   */\n  getBlob(): Blob | undefined {\n    return this.binaryData?.blob;\n  }\n\n  /**\n   * Check if this resource is a binary resource\n   * @returns True if this resource is a binary resource, false if not,\n   * undefined if unknown\n   *\n   * @example\n   * ```typescript\n   * // Logs \"undefined\"\n   * console.log(leaf.isBinary());\n   * const result = await leaf.read();\n   * if (!result.isError) {\n   *   // Logs \"true\"\n   *   console.log(leaf.isBinary());\n   * }\n   * ```\n   */\n  isBinary(): boolean | undefined {\n    if (!this.didInitialFetch) {\n      return undefined;\n    }\n    return !!this.binaryData;\n  }\n\n  /**\n   * Check if this resource is a data (RDF) resource\n   * @returns True if this resource is a data resource, false if not, undefined\n   * if unknown\n   *\n   * @example\n   * ```typescript\n   * // Logs \"undefined\"\n   * console.log(leaf.isDataResource());\n   * const result = await leaf.read();\n   * if (!result.isError) {\n   *   // Logs \"true\"\n   *   console.log(leaf.isDataResource());\n   * }\n   * ```\n   */\n  isDataResource(): boolean | undefined {\n    if (!this.didInitialFetch) {\n      return undefined;\n    }\n    return !this.binaryData;\n  }\n\n  /**\n   * ===========================================================================\n   * READ METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * @internal\n   * A helper method updates this leaf's internal state upon read success\n   * @param result - the result of the read success\n   */\n  protected updateWithReadSuccess(\n    result: BinaryReadSuccess | DataReadSuccess | AbsentReadSuccess<this>,\n  ): void {\n    super.updateWithReadSuccess(result);\n    if (result.type === \"binaryReadSuccess\") {\n      this.binaryData = { blob: result.blob, mimeType: result.mimeType };\n    } else {\n      this.binaryData = undefined;\n    }\n  }\n\n  /**\n   * Reads the leaf by making a request\n   * @returns A read result\n   *\n   * @example\n   * ```typescript\n   * const result = await leaf.read();\n   * if (result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async read(): Promise<ReadLeafResult> {\n    const result = (await this.handleRead()) as ReadLeafResult;\n    if (result.isError) return result;\n    return { ...result, resource: this };\n  }\n\n  /**\n   * @internal\n   * Converts the current state of this leaf to a readResult\n   * @returns a ReadLeafResult\n   */\n  protected toReadResult(): ReadLeafResult {\n    if (this.isAbsent()) {\n      return new AbsentReadSuccess(this, true);\n    } else if (this.isBinary()) {\n      return new BinaryReadSuccess(\n        this,\n        true,\n        this.binaryData!.blob,\n        this.binaryData!.mimeType,\n      );\n    } else {\n      return new DataReadSuccess(this, true);\n    }\n  }\n\n  /**\n   * Makes a request to read this leaf if it hasn't been fetched yet. If it has,\n   * return the cached informtation\n   * @returns a ReadLeafResult\n   *\n   * @example\n   * ```typescript\n   * const result = await leaf.read();\n   * if (!result.isError) {\n   *   // Will execute without making a request\n   *   const result2 = await leaf.readIfUnfetched();\n   * }\n   * ```\n   */\n  async readIfUnfetched(): Promise<ReadLeafResult> {\n    return super.readIfUnfetched() as Promise<ReadLeafResult>;\n  }\n\n  /**\n   * ===========================================================================\n   * PARENT CONTAINER METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * Gets the parent container for this leaf by making a request\n   * @returns The parent container\n   *\n   * @example\n   * ```typescript\n   * const leaf = solidLdoDataset\n   *   .getResource(\"https://example.com/container/resource.ttl\");\n   * const leafParent = await leaf.getParentContainer();\n   * if (!leafParent.isError) {\n   *   // Logs \"https://example.com/container/\"\n   *   console.log(leafParent.uri);\n   * }\n   * ```\n   */\n  async getParentContainer(): Promise<SolidContainer> {\n    const parentUri = getParentUri(this.uri)!;\n    return this.context.dataset.getResource(parentUri);\n  }\n\n  /**\n   * Gets the root container for this leaf.\n   * @returns The root container for this leaf\n   *\n   * @example\n   * Suppose the root container is at `https://example.com/`\n   *\n   * ```typescript\n   * const leaf = ldoSolidDataset\n   *   .getResource(\"https://example.com/container/resource.ttl\");\n   * const rootContainer = await leaf.getRootContainerByTraversal();\n   * if (!rootContainer.isError) {\n   *   // logs \"https://example.com/\"\n   *   console.log(rootContainer.uri);\n   * }\n   * ```\n   */\n  async getRootContainerByTraversal(): Promise<\n    SolidContainer | CheckRootResultError | NoRootContainerError<SolidContainer>\n  > {\n    // Check to see if this document has a pim:storage if so, use that\n\n    // If not, traverse the tree\n    const parent = await this.getParentContainer();\n    return parent.getRootContainerByTraversal();\n  }\n\n  /**\n   * ===========================================================================\n   * DELETE METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * @internal\n   * A helper method updates this leaf's internal state upon delete success\n   * @param result - the result of the delete success\n   */\n  public updateWithDeleteSuccess(result: DeleteSuccess<this>) {\n    super.updateWithDeleteSuccess(result);\n    this.binaryData = undefined;\n  }\n\n  /**\n   * Deletes this leaf and all its contents\n   * @returns A Delete result for this leaf\n   *\n   * ```typescript\n   * const result = await container.leaf();\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async delete(): Promise<DeleteResult<this>> {\n    return this.handleDelete();\n  }\n\n  /**\n   * @internal\n   */\n  protected async handleDelete(): Promise<DeleteResult<this>> {\n    return super.handleDelete() as Promise<DeleteResult<this>>;\n  }\n\n  /**\n   * ===========================================================================\n   * CREATE METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * A helper method updates this leaf's internal state upon create success\n   * @param _result - the result of the create success\n   */\n  protected updateWithCreateSuccess(_result: ResourceSuccess<this>): void {\n    this.binaryData = undefined;\n  }\n\n  /**\n   * Creates a leaf at this URI and overwrites any that already exists\n   * @returns LeafCreateAndOverwriteResult\n   *\n   * @example\n   * ```typescript\n   * const result = await leaf.createAndOverwrite();\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async createAndOverwrite(): Promise<LeafCreateAndOverwriteResult> {\n    const createResult =\n      (await this.handleCreateAndOverwrite()) as LeafCreateAndOverwriteResult;\n    if (createResult.isError) return createResult;\n    return { ...createResult, resource: this };\n  }\n\n  /**\n   * Creates a leaf at this URI if the leaf doesn't already exist\n   * @returns LeafCreateIfAbsentResult\n   *\n   * @example\n   * ```typescript\n   * const result = await leaf.createIfAbsent();\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async createIfAbsent(): Promise<LeafCreateIfAbsentResult> {\n    const createResult =\n      (await this.handleCreateIfAbsent()) as LeafCreateIfAbsentResult;\n    if (createResult.isError) return createResult;\n    return { ...createResult, resource: this };\n  }\n\n  /**\n   * ===========================================================================\n   * UPLOAD METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * Uploads a binary resource to this URI. If there is already a resource\n   * present at this URI, it will be overwritten\n   *\n   * @param blob - the Blob of the binary\n   * @param mimeType - the MimeType of the binary\n   * @returns A LeafCreateAndOverwriteResult\n   *\n   * @example\n   * ```typescript\n   * const result = await leaf.uploadAndOverwrite(\n   *   new Blob(\"some text.\"),\n   *   \"text/txt\",\n   * );\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async uploadAndOverwrite(\n    blob: Blob,\n    mimeType: string,\n  ): Promise<LeafCreateAndOverwriteResult> {\n    const result = await this.requester.upload(blob, mimeType, true);\n    this.status = result;\n    if (result.isError) {\n      this.emit(\"update\");\n      return result;\n    }\n    super.updateWithCreateSuccess(result);\n    this.binaryData = { blob, mimeType };\n    this.emitThisAndParent();\n    return { ...result, resource: this };\n  }\n\n  /**\n   * Uploads a binary resource to this URI tf there not is already a resource\n   * present at this URI.\n   *\n   * @param blob - the Blob of the binary\n   * @param mimeType - the MimeType of the binary\n   * @returns A LeafCreateIfAbsentResult\n   *\n   * @example\n   * ```typescript\n   * const result = await leaf.uploadIfAbsent(\n   *   new Blob(\"some text.\"),\n   *   \"text/txt\",\n   * );\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async uploadIfAbsent(\n    blob: Blob,\n    mimeType: string,\n  ): Promise<LeafCreateIfAbsentResult> {\n    const result = await this.requester.upload(blob, mimeType);\n    this.status = result;\n    if (result.isError) {\n      this.emit(\"update\");\n      return result;\n    }\n    super.updateWithCreateSuccess(result);\n    this.binaryData = { blob, mimeType };\n    this.emitThisAndParent();\n    return { ...result, resource: this };\n  }\n\n  /**\n   * ===========================================================================\n   * UPDATE METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * Updates a data resource with the changes provided\n   * @param changes - Dataset changes that will be applied to the resoruce\n   * @returns An UpdateResult\n   *\n   * @example\n   * ```typescript\n   * import {\n   *   updateDataResource,\n   *   transactionChanges,\n   *   changeData,\n   *   createSolidLdoDataset,\n   * } from \"@ldo/solid\";\n   *\n   * //...\n   *\n   * // Get a Linked Data Object\n   * const profile = solidLdoDataset\n   *   .usingType(ProfileShapeType)\n   *   .fromSubject(\"https://example.com/profile#me\");\n   * cosnt resource = solidLdoDataset\n   *   .getResource(\"https://example.com/profile\");\n   * // Create a transaction to change data\n   * const cProfile = changeData(profile, resource);\n   * cProfile.name = \"John Doe\";\n   * // Get data in \"DatasetChanges\" form\n   * const datasetChanges = transactionChanges(someLinkedDataObject);\n   * // Use \"update\" to apply the changes\n   * cosnt result = resource.update(datasetChanges);\n   * ```\n   */\n  async update(\n    changes: DatasetChanges<Quad>,\n  ): Promise<UpdateResult<SolidLeaf>> {\n    const result = await this.requester.updateDataResource(changes);\n    this.status = result;\n    if (result.isError) {\n      this.emit(\"update\");\n      return result;\n    }\n    this.binaryData = undefined;\n    this.absent = false;\n    this.emitThisAndParent();\n    return { ...result, resource: this };\n  }\n}\n"],"mappings":"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"}