{"version":3,"file":"SolidResource.mjs","names":[],"sources":["../../src/resources/SolidResource.ts"],"sourcesContent":["import type {\n  ConnectedContext,\n  ConnectedResult,\n  IgnoredInvalidUpdateSuccess,\n  ReadSuccess,\n  Resource,\n  ResourceEventEmitter,\n  ResourceSuccess,\n  SubscriptionCallbacks,\n  Unfetched,\n} from \"@ldo/connected\";\nimport type { SolidContainerUri, SolidLeafUri } from \"../types\";\nimport EventEmitter from \"events\";\nimport type { SolidConnectedPlugin } from \"../SolidConnectedPlugin\";\nimport type { BatchedRequester } from \"../requester/BatchedRequester\";\nimport type { WacRule } from \"../wac/WacRule\";\nimport type { NotificationSubscription } from \"@ldo/connected\";\nimport { Websocket2023NotificationSubscription } from \"../notifications/Websocket2023NotificationSubscription\";\nimport { getParentUri } from \"../util/rdfUtils\";\nimport { isReadSuccess } from \"../requester/results/success/SolidReadSuccess\";\nimport type {\n  ReadContainerResult,\n  ReadLeafResult,\n} from \"../requester/requests/readResource\";\nimport { DeleteSuccess } from \"../requester/results/success/DeleteSuccess\";\nimport {\n  updateDatasetOnSuccessfulDelete,\n  type DeleteResult,\n} from \"../requester/requests/deleteResource\";\nimport type {\n  ContainerCreateAndOverwriteResult,\n  ContainerCreateIfAbsentResult,\n  LeafCreateAndOverwriteResult,\n  LeafCreateIfAbsentResult,\n} from \"../requester/requests/createDataResource\";\nimport type { SolidContainer } from \"./SolidContainer\";\nimport type { CheckRootResultError } from \"../requester/requests/checkRootContainer\";\nimport type { NoRootContainerError } from \"../requester/results/error/NoRootContainerError\";\nimport type { SolidLeaf } from \"./SolidLeaf\";\nimport type { GetWacUriError } from \"../wac/getWacUri\";\nimport { getWacUri, type GetWacUriResult } from \"../wac/getWacUri\";\nimport type { GetWacRuleError } from \"../wac/getWacRule\";\nimport { getWacRuleWithAclUri } from \"../wac/getWacRule\";\nimport type { SetWacRuleResult } from \"../wac/setWacRule\";\nimport { setWacRuleForAclUri } from \"../wac/setWacRule\";\nimport { NoncompliantPodError } from \"../requester/results/error/NoncompliantPodError\";\nimport type { SolidNotificationMessage } from \"../notifications/SolidNotificationMessage\";\nimport type { CreateSuccess } from \"../requester/results/success/CreateSuccess\";\nimport { GetWacUriSuccess } from \"../wac/results/GetWacUriSuccess\";\nimport { GetWacRuleSuccess } from \"../wac/results/GetWacRuleSuccess\";\nimport { type DatasetChanges, namedNode } from \"@ldo/rdf-utils\";\nimport type { UpdateResult } from \"../requester/requests/updateDataResource\";\nimport {\n  getStorageDescriptionUri,\n  type GetStorageDescriptionUriError,\n  type GetStorageDescriptionUriResult,\n} from \"../requester/requests/getStorageDescription.js\";\nimport { GetStorageDescriptionUriSuccess } from \"../requester/results/success/StorageDescriptionSuccess.js\";\n\n/**\n * Statuses shared between both Leaf and Container\n */\nexport type SharedStatuses<ResourceType extends SolidLeaf | SolidContainer> =\n  | Unfetched<ResourceType>\n  | DeleteResult<ResourceType>\n  | CreateSuccess<ResourceType>;\n\nexport abstract class SolidResource\n  extends (EventEmitter as new () => ResourceEventEmitter)\n  implements Resource<SolidLeafUri | SolidContainerUri>\n{\n  /**\n   * @internal\n   * The ConnectedContext from the Parent Dataset\n   */\n  protected readonly context: ConnectedContext<SolidConnectedPlugin[]>;\n\n  /**\n   * The uri of the resource\n   */\n  abstract readonly uri: SolidLeafUri | SolidContainerUri;\n\n  /**\n   * The type of resource (leaf or container)\n   */\n  abstract readonly type: \"SolidLeaf\" | \"SolidContainer\";\n\n  /**\n   * The status of the last request made for this resource\n   */\n  abstract status: ConnectedResult;\n\n  /**\n   * @internal\n   * Batched Requester for the Resource\n   */\n  protected abstract readonly requester: BatchedRequester<\n    SolidLeaf | SolidContainer\n  >;\n\n  /**\n   * @internal\n   * True if this resource has been fetched at least once\n   */\n  protected didInitialFetch: boolean = false;\n\n  /**\n   * @internal\n   * True if this resource has been fetched but does not exist\n   */\n  protected absent: boolean | undefined;\n\n  /**\n   * @internal\n   * If a wac uri is fetched, it is cached here\n   */\n  protected wacUri?: SolidLeafUri;\n\n  /**\n   * @internal\n   * If a wac rule was fetched, it is cached here\n   */\n  protected wacRule?: WacRule;\n\n  /**\n   * @internal\n   * Handles notification subscriptions\n   */\n  protected notificationSubscription: NotificationSubscription<\n    SolidConnectedPlugin,\n    SolidNotificationMessage\n  >;\n\n  /**\n   * Indicates that resources are not errors\n   */\n  public readonly isError: false = false as const;\n\n  /**\n   * @internal\n   * If a storage description URI was fetched, it is cached here\n   *\n   * https://solidproject.org/TR/protocol#server-storage-description\n   */\n  protected storageDescriptionUri?: SolidLeafUri;\n\n  /**\n   * @internal\n   * If a root container uri as fetched from storage description, it is cached here\n   *\n   * https://solidproject.org/TR/protocol#storage-description-statements\n   */\n  protected rootContainerFromStorageDescriptionUri?: SolidContainerUri;\n\n  /**\n   * @param context - SolidLdoDatasetContext for the parent dataset\n   */\n  constructor(context: ConnectedContext<SolidConnectedPlugin[]>) {\n    super();\n    this.context = context;\n    this.notificationSubscription = new Websocket2023NotificationSubscription(\n      this as unknown as SolidLeaf | SolidContainer,\n      this.onNotification.bind(this),\n      this.context,\n    );\n  }\n\n  /**\n   * ===========================================================================\n   * GETTERS\n   * ===========================================================================\n   */\n\n  /**\n   * Checks to see if this resource is loading in any way\n   * @returns true if the resource is currently loading\n   *\n   * @example\n   * ```typescript\n   * resource.read().then(() => {\n   *   // Logs \"false\"\n   *   console.log(resource.isLoading())\n   * });\n   * // Logs \"true\"\n   * console.log(resource.isLoading());\n   * ```\n   */\n  isLoading(): boolean {\n    return this.requester.isLoading();\n  }\n\n  /**\n   * Checks to see if this resource is being created\n   * @returns true if the resource is currently being created\n   *\n   * @example\n   * ```typescript\n   * resource.read().then(() => {\n   *   // Logs \"false\"\n   *   console.log(resource.isCreating())\n   * });\n   * // Logs \"true\"\n   * console.log(resource.isCreating());\n   * ```\n   */\n  isCreating(): boolean {\n    return this.requester.isCreating();\n  }\n\n  /**\n   * Checks to see if this resource is being read\n   * @returns true if the resource is currently being read\n   *\n   * @example\n   * ```typescript\n   * resource.read().then(() => {\n   *   // Logs \"false\"\n   *   console.log(resource.isReading())\n   * });\n   * // Logs \"true\"\n   * console.log(resource.isReading());\n   * ```\n   */\n  isReading(): boolean {\n    return this.requester.isReading();\n  }\n\n  /**\n   * Checks to see if this resource is being deleted\n   * @returns true if the resource is currently being deleted\n   *\n   * @example\n   * ```typescript\n   * resource.read().then(() => {\n   *   // Logs \"false\"\n   *   console.log(resource.isDeleting())\n   * });\n   * // Logs \"true\"\n   * console.log(resource.isDeleting());\n   * ```\n   */\n  isDeleting(): boolean {\n    return this.requester.isDeletinng();\n  }\n\n  /**\n   * Checks to see if this resource is being read for the first time\n   * @returns true if the resource is currently being read for the first time\n   *\n   * @example\n   * ```typescript\n   * resource.read().then(() => {\n   *   // Logs \"false\"\n   *   console.log(resource.isDoingInitialFetch())\n   * });\n   * // Logs \"true\"\n   * console.log(resource.isDoingInitialFetch());\n   * ```\n   */\n  isDoingInitialFetch(): boolean {\n    return this.isReading() && !this.isFetched();\n  }\n\n  /**\n   * Checks to see if this resource is being read for a subsequent time\n   * @returns true if the resource is currently being read for a subsequent time\n   *\n   * @example\n   * ```typescript\n   * await resource.read();\n   * resource.read().then(() => {\n   *   // Logs \"false\"\n   *   console.log(resource.isCreating())\n   * });\n   * // Logs \"true\"\n   * console.log(resource.isCreating());\n   * ```\n   */\n  isReloading(): boolean {\n    return this.isReading() && this.isFetched();\n  }\n\n  /**\n   * ===========================================================================\n   * CHECKERS\n   * ===========================================================================\n   */\n\n  /**\n   * Check to see if this resource has been fetched\n   * @returns true if this resource has been fetched before\n   *\n   * @example\n   * ```typescript\n   * // Logs \"false\"\n   * console.log(resource.isFetched());\n   * const result = await resource.read();\n   * if (!result.isError) {\n   *   // Logs \"true\"\n   *   console.log(resource.isFetched());\n   * }\n   * ```\n   */\n  isFetched(): boolean {\n    return this.didInitialFetch;\n  }\n\n  /**\n   * Check to see if this resource is currently unfetched\n   * @returns true if the resource is currently unfetched\n   *\n   * @example\n   * ```typescript\n   * // Logs \"true\"\n   * console.log(resource.isUnetched());\n   * const result = await resource.read();\n   * if (!result.isError) {\n   *   // Logs \"false\"\n   *   console.log(resource.isUnfetched());\n   * }\n   * ```\n   */\n  isUnfetched(): boolean {\n    return !this.didInitialFetch;\n  }\n\n  /**\n   * Is this resource currently absent (it does not exist)\n   * @returns true if the resource is absent, false if not, undefined if unknown\n   *\n   * @example\n   * ```typescript\n   * // Logs \"undefined\"\n   * console.log(resource.isAbsent());\n   * const result = await resource.read();\n   * if (!result.isError) {\n   *   // False if the resource exists, true if it does not\n   *   console.log(resource.isAbsent());\n   * }\n   * ```\n   */\n  isAbsent(): boolean | undefined {\n    return this.absent;\n  }\n\n  /**\n   * Is this resource currently present on the Pod\n   * @returns false if the resource is absent, true if not, undefined if unknown\n   *\n   * @example\n   * ```typescript\n   * // Logs \"undefined\"\n   * console.log(resource.isPresent());\n   * const result = await resource.read();\n   * if (!result.isError) {\n   *   // True if the resource exists, false if it does not\n   *   console.log(resource.isPresent());\n   * }\n   * ```\n   */\n  isPresent(): boolean | undefined {\n    return this.absent === undefined ? undefined : !this.absent;\n  }\n\n  /**\n   * Is this resource currently listening to notifications from this document\n   * @returns true if the resource is subscribed to notifications, false if not\n   *\n   * @example\n   * ```typescript\n   * await resource.subscribeToNotifications();\n   * // Logs \"true\"\n   * console.log(resource.isSubscribedToNotifications());\n   * ```\n   */\n  isSubscribedToNotifications(): boolean {\n    return this.notificationSubscription.isSubscribedToNotifications();\n  }\n\n  /**\n   * ===========================================================================\n   * HELPER METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * @internal\n   * Emits an update event for both this resource and the parent\n   */\n  protected emitThisAndParent() {\n    this.emit(\"update\");\n    const parentUri = getParentUri(this.uri);\n    if (parentUri) {\n      const parentContainer = this.context.dataset.getResource(parentUri);\n      parentContainer.emit(\"update\");\n    }\n  }\n\n  /**\n   * ===========================================================================\n   * READ METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * @internal\n   * A helper method updates this resource's internal state upon read success\n   * @param result - the result of the read success\n   */\n  protected updateWithReadSuccess(result: ReadSuccess<Resource>) {\n    this.absent = result.type === \"absentReadSuccess\";\n    this.didInitialFetch = true;\n  }\n\n  /**\n   * @internal\n   * A helper method that handles the core functions for reading\n   * @returns ReadResult\n   */\n  protected async handleRead(): Promise<ReadContainerResult | ReadLeafResult> {\n    const result = await this.requester.read();\n    this.status = result;\n    if (result.isError) {\n      this.emit(\"update\");\n      return result;\n    }\n    this.updateWithReadSuccess(result);\n    this.emitThisAndParent();\n    return result;\n  }\n\n  /**\n   * @internal\n   * Converts the current state of this resource to a readResult\n   * @returns a ReadResult\n   */\n  protected abstract toReadResult(): ReadLeafResult | ReadContainerResult;\n\n  /**\n   * Reads the resource\n   */\n  abstract read(): Promise<ReadLeafResult | ReadContainerResult>;\n\n  /**\n   * Reads the resource if it isn't fetched yet\n   * @returns a ReadResult\n   */\n  async readIfUnfetched(): Promise<ReadLeafResult | ReadContainerResult> {\n    if (this.didInitialFetch) {\n      const readResult = this.toReadResult();\n      this.status = readResult;\n      return readResult;\n    }\n    return this.read();\n  }\n\n  /**\n   * ===========================================================================\n   * DELETE METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * @internal\n   * A helper method updates this resource's internal state upon delete success\n   * @param result - the result of the delete success\n   */\n  public updateWithDeleteSuccess(_result: DeleteSuccess<SolidResource>) {\n    this.absent = true;\n    this.didInitialFetch = true;\n  }\n\n  /**\n   * @internal\n   * Helper method that handles the core functions for deleting a resource\n   * @returns DeleteResult\n   */\n  protected async handleDelete(): Promise<\n    DeleteResult<SolidLeaf | SolidContainer>\n  > {\n    const result = await this.requester.delete();\n    this.status = result;\n    if (result.isError) {\n      this.emit(\"update\");\n      return result;\n    }\n    this.updateWithDeleteSuccess(result);\n    this.emitThisAndParent();\n    return result;\n  }\n\n  /**\n   * ===========================================================================\n   * CREATE METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * A helper method updates this resource's internal state upon create success\n   * @param _result - the result of the create success\n   */\n  protected updateWithCreateSuccess(result: ResourceSuccess<Resource>) {\n    this.absent = false;\n    this.didInitialFetch = true;\n    if (isReadSuccess(result)) {\n      this.updateWithReadSuccess(result as ReadSuccess<this>);\n    }\n  }\n\n  /**\n   * Creates a resource at this URI and overwrites any that already exists\n   * @returns CreateAndOverwriteResult\n   *\n   * @example\n   * ```typescript\n   * const result = await resource.createAndOverwrite();\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  abstract createAndOverwrite(): Promise<\n    ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult\n  >;\n\n  /**\n   * @internal\n   * Helper method that handles the core functions for creating and overwriting\n   * a resource\n   * @returns DeleteResult\n   */\n  protected async handleCreateAndOverwrite(): Promise<\n    ContainerCreateAndOverwriteResult | LeafCreateAndOverwriteResult\n  > {\n    const result = await this.requester.createDataResource(true);\n    this.status = result;\n    if (result.isError) {\n      this.emit(\"update\");\n      return result;\n    }\n    this.updateWithCreateSuccess(result);\n    this.emitThisAndParent();\n    return result;\n  }\n\n  /**\n   * Creates a resource at this URI if the resource doesn't already exist\n   * @returns CreateIfAbsentResult\n   *\n   * @example\n   * ```typescript\n   * const result = await leaf.createIfAbsent();\n   * if (!result.isError) {\n   *   // Do something\n   * }\n   * ```\n   */\n  abstract createIfAbsent(): Promise<\n    ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult\n  >;\n\n  /**\n   * @internal\n   * Helper method that handles the core functions for creating a resource if\n   *  absent\n   * @returns DeleteResult\n   */\n  protected async handleCreateIfAbsent(): Promise<\n    ContainerCreateIfAbsentResult | LeafCreateIfAbsentResult\n  > {\n    const result = await this.requester.createDataResource();\n    this.status = result;\n    if (result.isError) {\n      this.emit(\"update\");\n      return result;\n    }\n    this.updateWithCreateSuccess(result);\n    this.emitThisAndParent();\n    return result;\n  }\n\n  /**\n   * UPDATE METHODS\n   */\n  abstract update(\n    datasetChanges: DatasetChanges,\n  ): Promise<\n    UpdateResult<SolidLeaf> | IgnoredInvalidUpdateSuccess<SolidContainer>\n  >;\n\n  /**\n   * ===========================================================================\n   * PARENT CONTAINER METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * Retrieves the URI for the storage description of this resource\n   * @param options - set the \"ignoreCache\" field to true to ignore cached URI\n   * @returns results, containing SolidLeafUri when successful\n   *\n   * note: this is based on this.getWacUri method\n   */\n  protected async getStorageDescriptionUri(options?: {\n    ignoreCache: boolean;\n  }): Promise<GetStorageDescriptionUriResult<SolidLeaf | SolidContainer>> {\n    const thisAsLeafOrContainer = this as unknown as SolidLeaf | SolidContainer;\n    // Get the storage description if not already present\n    if (!options?.ignoreCache && this.storageDescriptionUri) {\n      return new GetStorageDescriptionUriSuccess(\n        thisAsLeafOrContainer,\n        this.storageDescriptionUri,\n      );\n    }\n\n    const storageDescriptionUriResult = await getStorageDescriptionUri(\n      thisAsLeafOrContainer,\n      { fetch: this.context.solid.fetch },\n    );\n    if (storageDescriptionUriResult.isError) {\n      return storageDescriptionUriResult;\n    }\n    this.storageDescriptionUri =\n      storageDescriptionUriResult.storageDescriptionUri;\n    return storageDescriptionUriResult;\n  }\n\n  /**\n   * Gets the root container for this resource.\n   * @returns The root container for this resource\n   *\n   * @example\n   * Suppose the root container is at `https://example.com/`\n   *\n   * ```typescript\n   * const resource = ldoSolidDataset\n   *   .getResource(\"https://example.com/container/resource.ttl\");\n   * const rootContainer = await resource.getRootContainer();\n   * if (!rootContainer.isError) {\n   *   // logs \"https://example.com/\"\n   *   console.log(rootContainer.uri);\n   * }\n   * ```\n   */\n  async getRootContainer(): Promise<\n    | SolidContainer\n    | CheckRootResultError\n    | NoRootContainerError<SolidLeaf | SolidContainer>\n  > {\n    const result = await this.getRootContainerFromStorageDescription();\n\n    if (!result.isError) {\n      // some dependencies may assume that the root container has been fetched\n      // so we make sure it is, to avoid a breaking change\n      await result.readIfUnfetched();\n      return result;\n    }\n\n    // if root container has not been found from storage description, fall back to traversal\n    return await this.getRootContainerByTraversal();\n  }\n\n  /**\n   * Gets the root container from this resource's storage description\n   * https://solidproject.org/TR/protocol#server-storage-description\n   *\n   * Consider getRootContainer() instead, which tries multiple discovery strategies.\n   *\n   * @param options - Options object\n   * @param options.ignoreCache {boolean} - ignore cached storage resource URI and root container values\n   *\n   * @returns SolidContainer or error objects\n   */\n  async getRootContainerFromStorageDescription(options?: {\n    ignoreCache: boolean;\n  }): Promise<\n    SolidContainer | GetStorageDescriptionUriError<SolidContainer | SolidLeaf>\n  > {\n    let rootContainerUri: SolidContainerUri;\n\n    // Return the root container if it's already cached\n    if (!options?.ignoreCache && this.rootContainerFromStorageDescriptionUri) {\n      rootContainerUri = this.rootContainerFromStorageDescriptionUri;\n    } else {\n      // Get storage description URI\n      const storageDescriptionUriResult =\n        await this.getStorageDescriptionUri(options);\n      if (storageDescriptionUriResult.isError)\n        return storageDescriptionUriResult;\n\n      // // Get root container from storage description URI\n      const storageDescriptionResource = this.context.dataset.getResource(\n        storageDescriptionUriResult.storageDescriptionUri,\n      );\n      const result = await storageDescriptionResource.readIfUnfetched();\n      if (result.isError) return result;\n\n      const rootContainerQuads = this.context.dataset.match(\n        null,\n        namedNode(\"http://www.w3.org/1999/02/22-rdf-syntax-ns#type\"),\n        namedNode(\"http://www.w3.org/ns/pim/space#Storage\"),\n        namedNode(storageDescriptionUriResult.storageDescriptionUri),\n      );\n\n      // https://solidproject.org/TR/protocol#storage-description-statements\n      if (rootContainerQuads.size !== 1) {\n        return new NoncompliantPodError(\n          storageDescriptionResource, // storage description, or this resource?\n          \"There should be one storage listed in storage description resource.\",\n        );\n      }\n\n      rootContainerUri = rootContainerQuads.toArray()[0].subject\n        .value as SolidContainerUri;\n    }\n    const rootContainer = this.context.dataset.getResource(rootContainerUri);\n    return rootContainer;\n  }\n\n  /**\n   * https://solidproject.org/TR/protocol#client-storage-disovery\n   */\n  abstract getRootContainerByTraversal(): Promise<\n    | SolidContainer\n    | CheckRootResultError\n    | NoRootContainerError<SolidLeaf | SolidContainer>\n  >;\n\n  abstract getParentContainer(): Promise<\n    SolidContainer | CheckRootResultError | undefined\n  >;\n\n  /**\n   * ===========================================================================\n   * WEB ACCESS CONTROL METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * Retrieves the URI for the web access control (WAC) rules for this resource\n   * @param options - set the \"ignoreCache\" field to true to ignore any cached\n   * information on WAC rules.\n   * @returns WAC Rules results\n   */\n  protected async getWacUri(options?: {\n    ignoreCache: boolean;\n  }): Promise<GetWacUriResult<SolidLeaf | SolidContainer>> {\n    const thisAsLeafOrContainer = this as unknown as SolidLeaf | SolidContainer;\n    // Get the wacUri if not already present\n    if (!options?.ignoreCache && this.wacUri) {\n      return new GetWacUriSuccess(thisAsLeafOrContainer, this.wacUri);\n    }\n\n    const wacUriResult = await getWacUri(thisAsLeafOrContainer, {\n      fetch: this.context.solid.fetch,\n    });\n    if (wacUriResult.isError) {\n      return wacUriResult;\n    }\n    this.wacUri = wacUriResult.wacUri;\n    return wacUriResult;\n  }\n\n  /**\n   * Retrieves web access control (WAC) rules for this resource\n   * @param options - set the \"ignoreCache\" field to true to ignore any cached\n   * information on WAC rules.\n   * @returns WAC Rules results\n   *\n   * @example\n   * ```typescript\n   * const resource = ldoSolidDataset\n   *   .getResource(\"https://example.com/container/resource.ttl\");\n   * const wacRulesResult = await resource.getWac();\n   * if (!wacRulesResult.isError) {\n   *   const wacRules = wacRulesResult.wacRule;\n   *   // True if the resource is publicly readable\n   *   console.log(wacRules.public.read);\n   *   // True if authenticated agents can write to the resource\n   *   console.log(wacRules.authenticated.write);\n   *   // True if the given WebId has append access\n   *   console.log(\n   *     wacRules.agent[https://example.com/person1/profile/card#me].append\n   *   );\n   *   // True if the given WebId has control access\n   *   console.log(\n   *     wacRules.agent[https://example.com/person1/profile/card#me].control\n   *   );\n   * }\n   * ```\n   */\n  async getWac(options?: {\n    ignoreCache: boolean;\n  }): Promise<\n    | GetWacUriError<SolidContainer | SolidLeaf>\n    | GetWacRuleError<SolidContainer | SolidLeaf>\n    | GetWacRuleSuccess<SolidContainer | SolidLeaf>\n  > {\n    const thisAsLeafOrContainer = this as unknown as SolidLeaf | SolidContainer;\n    // Return the wac rule if it's already cached\n    if (!options?.ignoreCache && this.wacRule) {\n      return new GetWacRuleSuccess(thisAsLeafOrContainer, this.wacRule);\n    }\n\n    // Get the wac uri\n    const wacUriResult = await this.getWacUri(options);\n    if (wacUriResult.isError) return wacUriResult;\n\n    // Get the wac rule\n    const wacResult = await getWacRuleWithAclUri(\n      wacUriResult.wacUri,\n      thisAsLeafOrContainer,\n      {\n        fetch: this.context.solid.fetch,\n      },\n    );\n    if (wacResult.isError) return wacResult;\n    // If the wac rules was successfully found\n    if (wacResult.type === \"getWacRuleSuccess\") {\n      this.wacRule = wacResult.wacRule;\n      return wacResult;\n    }\n\n    // If the WacRule is absent\n    const parentResource = await this.getParentContainer();\n    if (parentResource?.isError) return parentResource;\n    if (!parentResource) {\n      return new NoncompliantPodError(\n        thisAsLeafOrContainer,\n        `Resource \"${this.uri}\" has no Effective ACL resource`,\n      );\n    }\n    return parentResource.getWac();\n  }\n\n  /**\n   * Sets access rules for a specific resource\n   * @param wacRule - the access rules to set\n   * @returns SetWacRuleResult\n   *\n   * @example\n   * ```typescript\n   * const resource = ldoSolidDataset\n   *   .getResource(\"https://example.com/container/resource.ttl\");\n   * const wacRulesResult = await resource.setWac({\n   *   public: {\n   *     read: true,\n   *     write: false,\n   *     append: false,\n   *     control: false\n   *   },\n   *   authenticated: {\n   *     read: true,\n   *     write: false,\n   *     append: true,\n   *     control: false\n   *   },\n   *   agent: {\n   *     \"https://example.com/person1/profile/card#me\": {\n   *       read: true,\n   *       write: true,\n   *       append: true,\n   *       control: true\n   *     }\n   *   }\n   * });\n   * ```\n   */\n  async setWac(\n    wacRule: WacRule,\n  ): Promise<\n    | GetWacUriError<SolidLeaf | SolidContainer>\n    | SetWacRuleResult<SolidLeaf | SolidContainer>\n  > {\n    const thisAsLeafOrContainer = this as unknown as SolidLeaf | SolidContainer;\n    const wacUriResult = await this.getWacUri();\n    if (wacUriResult.isError) return wacUriResult;\n\n    const result = await setWacRuleForAclUri(\n      wacUriResult.wacUri,\n      wacRule,\n      thisAsLeafOrContainer,\n      {\n        fetch: this.context.solid.fetch,\n      },\n    );\n    if (result.isError) {\n      this.emit(\"update\");\n      return result;\n    }\n    this.wacRule = result.wacRule;\n    return result;\n  }\n\n  /**\n   * ===========================================================================\n   * SUBSCRIPTION METHODS\n   * ===========================================================================\n   */\n\n  /**\n   * Activates Websocket subscriptions on this resource. Updates, deletions,\n   * and creations on this resource will be tracked and all changes will be\n   * relected in LDO's resources and graph.\n   *\n   * @param onNotificationError - A callback function if there is an error\n   * with notifications.\n   * @returns SubscriptionId: A string to use to unsubscribe\n   *\n   * @example\n   * ```typescript\n   * const resource = solidLdoDataset\n   *   .getResource(\"https://example.com/spiderman\");\n   * // A listener for if anything about spiderman in the global dataset is\n   * // changed. Note that this will also listen for any local changes as well\n   * // as changes to remote resources to which you have notification\n   * // subscriptions enabled.\n   * solidLdoDataset.addListener(\n   *   [namedNode(\"https://example.com/spiderman#spiderman\"), null, null, null],\n   *   () => {\n   *     // Triggers when the file changes on the Pod or locally\n   *     console.log(\"Something changed about SpiderMan\");\n   *   },\n   * );\n   *\n   * // Subscribe\n   * const subscriptionId = await testContainer.subscribeToNotifications({\n   *   // These are optional callbacks. A subscription will automatically keep\n   *   // the dataset in sync. Use these callbacks for additional functionality.\n   *   onNotification: (message) => console.log(message),\n   *   onNotificationError: (err) => console.log(err.message)\n   * });\n   * // ... From there you can wait for a file to be changed on the Pod.\n   */\n  async subscribeToNotifications(\n    callbacks?: SubscriptionCallbacks<SolidNotificationMessage>,\n  ): Promise<string> {\n    return await this.notificationSubscription.subscribeToNotifications(\n      callbacks,\n    );\n  }\n\n  /**\n   * @internal\n   * Function that triggers whenever a notification is recieved.\n   */\n  protected async onNotification(\n    message: SolidNotificationMessage,\n  ): Promise<void> {\n    const objectResource = this.context.dataset.getResource(message.object);\n    // Do Nothing if the resource is invalid.\n    if (objectResource.type === \"InvalidIdentifierResource\") return;\n    if (objectResource.type === \"SolidLeaf\") {\n      switch (message.type) {\n        case \"Update\":\n        case \"Add\":\n          await objectResource.read();\n          return;\n        case \"Delete\":\n        case \"Remove\":\n          // Delete the resource without have to make an additional read request\n          updateDatasetOnSuccessfulDelete(message.object, this.context.dataset);\n          objectResource.updateWithDeleteSuccess(\n            new DeleteSuccess(objectResource, true),\n          );\n          return;\n      }\n    }\n  }\n\n  /**\n   * Unsubscribes from changes made to this resource on the Pod\n   *\n   * @returns UnsubscribeResult\n   *\n   * @example\n   * ```typescript\n   * const subscriptionId = await testContainer.subscribeToNotifications();\n   * await testContainer.unsubscribeFromNotifications(subscriptionId);\n   * ```\n   */\n  async unsubscribeFromNotifications(subscriptionId: string): Promise<void> {\n    return this.notificationSubscription.unsubscribeFromNotification(\n      subscriptionId,\n    );\n  }\n\n  /**\n   * Unsubscribes from all notifications on this resource\n   *\n   * @returns UnsubscribeResult[]\n   *\n   * @example\n   * ```typescript\n   * const subscriptionResult = await testContainer.subscribeToNotifications();\n   * await testContainer.unsubscribeFromAllNotifications();\n   * ```\n   */\n  async unsubscribeFromAllNotifications(): Promise<void> {\n    return this.notificationSubscription.unsubscribeFromAllNotifications();\n  }\n}\n"],"mappings":"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"}