{"version":3,"file":"SolidContainer.mjs","names":[],"sources":["../../src/resources/SolidContainer.ts"],"sourcesContent":["import { namedNode } from \"@ldo/rdf-utils\";\nimport { ContainerBatchedRequester } from \"../requester/ContainerBatchedRequester\";\nimport type {\n  CheckRootResult,\n  CheckRootResultError,\n} from \"../requester/requests/checkRootContainer\";\nimport type {\n  ContainerCreateAndOverwriteResult,\n  ContainerCreateIfAbsentResult,\n  LeafCreateAndOverwriteResult,\n  LeafCreateIfAbsentResult,\n} from \"../requester/requests/createDataResource\";\nimport type {\n  DeleteResult,\n  DeleteResultError,\n} from \"../requester/requests/deleteResource\";\nimport type {\n  ReadContainerResult,\n  ReadResultError,\n} from \"../requester/requests/readResource\";\nimport type { DeleteSuccess } from \"../requester/results/success/DeleteSuccess\";\nimport type { ContainerReadSuccess } from \"../requester/results/success/SolidReadSuccess\";\nimport { getParentUri, ldpContains } from \"../util/rdfUtils\";\nimport { NoRootContainerError } from \"../requester/results/error/NoRootContainerError\";\nimport type { SharedStatuses } from \"./SolidResource\";\nimport { SolidResource } from \"./SolidResource\";\nimport type {\n  SolidContainerSlug,\n  SolidContainerUri,\n  SolidLeafSlug,\n} from \"../types\";\nimport type { ReadSuccess } from \"@ldo/connected\";\nimport { AggregateSuccess, IgnoredInvalidUpdateSuccess } from \"@ldo/connected\";\nimport {\n  Unfetched,\n  type ConnectedContext,\n  AggregateError,\n} from \"@ldo/connected\";\nimport type { SolidConnectedPlugin } from \"../SolidConnectedPlugin\";\nimport type { SolidLeaf } from \"./SolidLeaf\";\nimport type { HttpErrorResultType } from \"../requester/results/error/HttpErrorResult\";\nimport type { DatasetChanges } from \"@ldo/rdf-utils\";\n\n/**\n * Represents the current status of a specific container on a Pod as known by\n * LDO.\n *\n * @example\n * ```typescript\n * const container = solidLdoDataset\n *   .getResource(\"https://example.com/container/\");\n * ```\n */\nexport class SolidContainer extends SolidResource {\n  /**\n   * The URI of the container\n   */\n  readonly uri: SolidContainerUri;\n\n  /**\n   * @internal\n   * Batched Requester for the Container\n   */\n  protected requester: ContainerBatchedRequester;\n\n  /**\n   * @internal\n   * True if this is the root container, false if not, undefined if unknown\n   */\n  protected rootContainer: boolean | undefined;\n\n  /**\n   * Indicates that this resource is a container resource\n   */\n  readonly type = \"SolidContainer\" 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 container\n   */\n  status:\n    | SharedStatuses<this>\n    | ReadContainerResult\n    | ContainerCreateAndOverwriteResult\n    | ContainerCreateIfAbsentResult\n    | CheckRootResult;\n\n  /**\n   * @param uri - The uri of the container\n   * @param context - SolidLdoDatasetContext for the parent dataset\n   */\n  constructor(\n    uri: SolidContainerUri,\n    context: ConnectedContext<SolidConnectedPlugin[]>,\n  ) {\n    super(context);\n    this.uri = uri;\n    this.requester = new ContainerBatchedRequester(this, context);\n    this.status = new Unfetched(this);\n  }\n\n  /**\n   * Checks if this container is a root container\n   * @returns true if this container is a root container, false if not, and\n   * undefined if this is unknown at the moment.\n   *\n   * @example\n   * ```typescript\n   * // Returns \"undefined\" when the container is unfetched\n   * console.log(container.isRootContainer());\n   * const result = await container.read();\n   * if (!result.isError) {\n   *   // Returns true or false\n   *   console.log(container.isRootContainer());\n   * }\n   * ```\n   */\n  isRootContainer(): boolean | undefined {\n    return this.rootContainer;\n  }\n\n  /**\n   * ===========================================================================\n   * READ METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * @internal\n   * A helper method updates this container's internal state upon read success\n   * @param result - the result of the read success\n   */\n  protected updateWithReadSuccess(\n    result: ReadSuccess<this> | ContainerReadSuccess,\n  ): void {\n    super.updateWithReadSuccess(result);\n    if (result.type === \"containerReadSuccess\") {\n      this.rootContainer = (result as ContainerReadSuccess).isRootContainer;\n    }\n  }\n\n  /**\n   * Reads the container\n   * @returns A read result\n   *\n   * @example\n   * ```typescript\n   * const result = await container.read();\n   * if (result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async read(): Promise<ReadContainerResult> {\n    const result = (await this.handleRead()) as ReadContainerResult;\n    return { ...result, resource: this };\n  }\n\n  /**\n   * @internal\n   * Converts the current state of this container to a readResult\n   * @returns a ReadContainerResult\n   */\n  protected toReadResult(): ReadContainerResult {\n    if (this.isAbsent()) {\n      return {\n        isError: false,\n        type: \"absentReadSuccess\",\n        uri: this.uri,\n        recalledFromMemory: true,\n        resource: this,\n      };\n    } else {\n      return {\n        isError: false,\n        type: \"containerReadSuccess\",\n        uri: this.uri,\n        recalledFromMemory: true,\n        isRootContainer: this.isRootContainer()!,\n        resource: this,\n      };\n    }\n  }\n\n  /**\n   * Makes a request to read this container if it hasn't been fetched yet. If it\n   * has, return the cached informtation\n   * @returns a ReadContainerResult\n   *\n   * @example\n   * ```typescript\n   * const result = await container.read();\n   * if (!result.isError) {\n   *   // Will execute without making a request\n   *   const result2 = await container.readIfUnfetched();\n   * }\n   * ```\n   */\n  async readIfUnfetched(): Promise<ReadContainerResult> {\n    return super.readIfUnfetched() as Promise<ReadContainerResult>;\n  }\n\n  /**\n   * ===========================================================================\n   * PARENT CONTAINER METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * @internal\n   * Checks if this container is a root container by making a request\n   * @returns CheckRootResult\n   */\n  private async checkIfIsRootContainer(): Promise<CheckRootResult> {\n    const rootContainerResult = await this.requester.isRootContainer();\n    this.status = rootContainerResult;\n    if (rootContainerResult.isError) return rootContainerResult;\n    this.rootContainer = rootContainerResult.isRootContainer;\n    this.emit(\"update\");\n    return { ...rootContainerResult, resource: this };\n  }\n\n  /**\n   * Gets the root container of this container. If this container is the root\n   * container, this function returns itself.\n   *\n   * Consider getRootContainer() instead, which tries multiple discovery strategies.\n   *\n   * @returns The root container for this container or undefined if there is no\n   * root container.\n   *\n   * @example\n   * Suppose the root container is at `https://example.com/`\n   *\n   * ```typescript\n   * const container = ldoSolidDataset\n   *   .getResource(\"https://example.com/container/\");\n   * const rootContainer = await container.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    const parentContainerResult = await this.getParentContainer();\n    if (parentContainerResult?.isError) return parentContainerResult;\n    if (!parentContainerResult) {\n      return this.isRootContainer() ? this : new NoRootContainerError(this);\n    }\n    return parentContainerResult.getRootContainerByTraversal();\n  }\n\n  /**\n   * Gets the parent container for this container by making a request\n   * @returns The parent container or undefined if there is no parent container\n   * because this container is the root container\n   *\n   * @example\n   * Suppose the root container is at `https://example.com/`\n   *\n   * ```typescript\n   * const root = solidLdoDataset.getResource(\"https://example.com/\");\n   * const container = solidLdoDataset\n   *   .getResource(\"https://example.com/container\");\n   * const rootParent = await root.getParentContainer();\n   * console.log(rootParent); // Logs \"undefined\"\n   * const containerParent = await container.getParentContainer();\n   * if (!containerParent.isError) {\n   *   // Logs \"https://example.com/\"\n   *   console.log(containerParent.uri);\n   * }\n   * ```\n   */\n  async getParentContainer(): Promise<\n    SolidContainer | CheckRootResultError | undefined\n  > {\n    if (this.rootContainer === undefined) {\n      const checkResult = await this.checkIfIsRootContainer();\n      if (checkResult.isError) return checkResult;\n    }\n    if (this.rootContainer) return undefined;\n    const parentUri = getParentUri(this.uri);\n    if (!parentUri) {\n      return undefined;\n    }\n    return this.context.dataset.getResource(parentUri);\n  }\n\n  /**\n   * Lists the currently cached children of this container (no request is made)\n   * @returns An array of children\n   *\n   * ```typescript\n   * const result = await container.read();\n   * if (!result.isError) {\n   *   const children = container.children();\n   *   children.forEach((child) => {\n   *     console.log(child.uri);\n   *   });\n   * }\n   * ```\n   */\n  children(): (SolidContainer | SolidLeaf)[] {\n    const childQuads = this.context.dataset.match(\n      namedNode(this.uri),\n      ldpContains,\n      null,\n      namedNode(this.uri),\n    );\n    return childQuads.toArray().map((childQuad) => {\n      return this.context.dataset.getResource(childQuad.object.value) as\n        | SolidContainer\n        | SolidLeaf;\n    });\n  }\n\n  /**\n   * Returns a child resource with a given name (slug)\n   * @param slug - the given name for that child resource\n   * @returns the child resource (either a Leaf or Container depending on the\n   * name)\n   *\n   * @example\n   * ```typescript\n   * const root = solidLdoDataset.getResource(\"https://example.com/\");\n   * const container = solidLdoDataset.child(\"container/\");\n   * // Logs \"https://example.com/container/\"\n   * console.log(container.uri);\n   * const resource = container.child(\"resource.ttl\");\n   * // Logs \"https://example.com/container/resource.ttl\"\n   * console.log(resource.uri);\n   * ```\n   */\n  child(slug: SolidContainerSlug): SolidContainer;\n  child(slug: SolidLeafSlug): SolidLeaf;\n  child(slug: string): SolidLeaf | SolidContainer;\n  child(slug: string): SolidLeaf | SolidContainer {\n    return this.context.dataset.getResource(`${this.uri}${slug}`) as\n      | SolidLeaf\n      | SolidContainer;\n  }\n\n  /**\n   * ===========================================================================\n   * CHILD CREATORS\n   * ===========================================================================\n   */\n\n  /**\n   * Creates a resource and overwrites any existing resource that existed at the\n   * URI\n   *\n   * @param slug - the name of the resource\n   * @return the result of creating that resource\n   *\n   * @example\n   * ```typescript\n   * const container = solidLdoDataset\n   *   .getResource(\"https://example.com/container/\");\n   * cosnt result = await container.createChildAndOverwrite(\"resource.ttl\");\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  createChildAndOverwrite(\n    slug: SolidContainerSlug,\n  ): Promise<ContainerCreateAndOverwriteResult>;\n  createChildAndOverwrite(\n    slug: SolidLeafSlug,\n  ): Promise<LeafCreateAndOverwriteResult>;\n  createChildAndOverwrite(\n    slug: string,\n  ): Promise<ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult>;\n  createChildAndOverwrite(\n    slug: string,\n  ): Promise<ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult> {\n    return this.child(slug).createAndOverwrite();\n  }\n\n  /**\n   * Creates a resource only if that resource doesn't already exist on the Solid\n   * Pod\n   *\n   * @param slug - the name of the resource\n   * @return the result of creating that resource\n   *\n   * @example\n   * ```typescript\n   * const container = solidLdoDataset\n   *   .getResource(\"https://example.com/container/\");\n   * cosnt result = await container.createChildIfAbsent(\"resource.ttl\");\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  createChildIfAbsent(\n    slug: SolidContainerSlug,\n  ): Promise<ContainerCreateIfAbsentResult>;\n  createChildIfAbsent(slug: SolidLeafSlug): Promise<LeafCreateIfAbsentResult>;\n  createChildIfAbsent(\n    slug: string,\n  ): Promise<ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult>;\n  createChildIfAbsent(\n    slug: string,\n  ): Promise<ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult> {\n    return this.child(slug).createIfAbsent();\n  }\n\n  /**\n   * Creates a new binary resource and overwrites any existing resource that\n   * existed at the URI\n   *\n   * @param slug - the name of the resource\n   * @return the result of creating that resource\n   *\n   * @example\n   * ```typescript\n   * const container = solidLdoDataset\n   *   .getResource(\"https://example.com/container/\");\n   * cosnt result = await container.uploadChildAndOverwrite(\n   *   \"resource.txt\",\n   *   new Blob(\"some text.\"),\n   *   \"text/txt\",\n   * );\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async uploadChildAndOverwrite(\n    slug: SolidLeafSlug,\n    blob: Blob,\n    mimeType: string,\n  ): Promise<LeafCreateAndOverwriteResult> {\n    return this.child(slug).uploadAndOverwrite(blob, mimeType);\n  }\n\n  /**\n   * Creates a new binary resource and overwrites any existing resource that\n   * existed at the URI\n   *\n   * @param slug - the name of the resource\n   * @return the result of creating that resource\n   *\n   * @example\n   * ```typescript\n   * const container = solidLdoDataset\n   *   .getResource(\"https://example.com/container/\");\n   * cosnt result = await container.uploadChildIfAbsent(\n   *   \"resource.txt\",\n   *   new Blob(\"some text.\"),\n   *   \"text/txt\",\n   * );\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async uploadChildIfAbsent(\n    slug: SolidLeafSlug,\n    blob: Blob,\n    mimeType: string,\n  ): Promise<LeafCreateIfAbsentResult> {\n    return this.child(slug).uploadIfAbsent(blob, mimeType);\n  }\n\n  /**\n   * Deletes all contents in this container\n   * @returns An AggregateSuccess or Aggregate error corresponding with all the\n   * deleted resources\n   *\n   * @example\n   * ```typescript\n   * const result = container.clear();\n   * if (!result.isError) {\n   *   console.log(\"All deleted resources:\");\n   *   result.results.forEach((result) => console.log(result.uri));\n   * }\n   * ```\n   */\n  async clear(): Promise<\n    | AggregateSuccess<DeleteSuccess<SolidContainer | SolidLeaf>>\n    | AggregateError<\n        | DeleteResultError<SolidContainer | SolidLeaf>\n        | ReadResultError<SolidContainer | SolidLeaf>\n      >\n  > {\n    const readResult = await this.read();\n    if (readResult.isError) return new AggregateError([readResult]);\n    const results = (\n      await Promise.all(\n        this.children().map(async (child) => {\n          return child.delete();\n        }),\n      )\n    ).flat();\n    const errors = results.filter(\n      (value): value is HttpErrorResultType<this> => value.isError,\n    );\n    if (errors.length > 0) {\n      return new AggregateError(errors);\n    }\n    return new AggregateSuccess(\n      results as DeleteSuccess<SolidContainer | SolidLeaf>[],\n    );\n  }\n\n  /**\n   * Deletes this container and all its contents\n   * @returns A Delete result for this container\n   *\n   * ```typescript\n   * const result = await container.delete();\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async delete(): Promise<\n    | DeleteResult<this>\n    | AggregateError<\n        | DeleteResultError<SolidContainer | SolidLeaf>\n        | ReadResultError<SolidContainer | SolidLeaf>\n      >\n  > {\n    const clearResult = await this.clear();\n    if (clearResult.isError) return clearResult;\n    const deleteResult = await this.handleDelete();\n    if (deleteResult.isError) return deleteResult;\n    return { ...deleteResult, resource: this };\n  }\n\n  protected async handleDelete(): Promise<DeleteResult<this>> {\n    return super.handleDelete() as Promise<DeleteResult<this>>;\n  }\n\n  /**\n   * Creates a container at this URI and overwrites any that already exists\n   * @returns ContainerCreateAndOverwriteResult\n   *\n   * @example\n   * ```typescript\n   * const result = await container.createAndOverwrite();\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async createAndOverwrite(): Promise<ContainerCreateAndOverwriteResult> {\n    const createResult =\n      (await this.handleCreateAndOverwrite()) as ContainerCreateAndOverwriteResult;\n    if (createResult.isError) return createResult;\n    return { ...createResult, resource: this };\n  }\n\n  /**\n   * Creates a container at this URI if the container doesn't already exist\n   * @returns ContainerCreateIfAbsentResult\n   *\n   * @example\n   * ```typescript\n   * const result = await container.createIfAbsent();\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  async createIfAbsent(): Promise<ContainerCreateIfAbsentResult> {\n    const createResult =\n      (await this.handleCreateIfAbsent()) as ContainerCreateIfAbsentResult;\n    if (createResult.isError) return createResult;\n    return { ...createResult, resource: this };\n  }\n\n  /**\n   * You cannot update a Container, so we return an IgnoredInvalidUpdateSuccess\n   */\n  async update(\n    _datasetChanges: DatasetChanges,\n  ): Promise<IgnoredInvalidUpdateSuccess<this>> {\n    return new IgnoredInvalidUpdateSuccess(this);\n  }\n}\n"],"mappings":"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"}