You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2023/03/30 04:38:23 UTC

[incubator-opendal] branch main updated: feat(bindings/nodejs): Add more APIs and examples (#1799)

This is an automated email from the ASF dual-hosted git repository.

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new f199ca0d feat(bindings/nodejs): Add more APIs and examples (#1799)
f199ca0d is described below

commit f199ca0d2fff6522cefa1e129af747b2fef0186d
Author: Suyan <su...@gmail.com>
AuthorDate: Thu Mar 30 12:38:19 2023 +0800

    feat(bindings/nodejs): Add more APIs and examples (#1799)
    
    * feat(bindings/nodejs): Add more APIs and examples
    
    Signed-off-by: suyanhanx <su...@gmail.com>
    
    * reformat
    
    Signed-off-by: suyanhanx <su...@gmail.com>
    
    * chore: upgrade typedoc to support TypeScript 5
    
    Signed-off-by: suyanhanx <su...@gmail.com>
    
    * remove example
    
    Signed-off-by: suyanhanx <su...@gmail.com>
    
    * simplify presign docs
    
    Signed-off-by: suyanhanx <su...@gmail.com>
    
    ---------
    
    Signed-off-by: suyanhanx <su...@gmail.com>
---
 bindings/nodejs/examples/presign.js |  49 -------
 bindings/nodejs/index.d.ts          | 270 ++++++++++++++++++++++++++++++++++--
 bindings/nodejs/package.json        |   2 +-
 bindings/nodejs/src/lib.rs          | 242 +++++++++++++++++++++++++++++++-
 bindings/nodejs/yarn.lock           |  12 +-
 5 files changed, 505 insertions(+), 70 deletions(-)

diff --git a/bindings/nodejs/examples/presign.js b/bindings/nodejs/examples/presign.js
deleted file mode 100644
index 740cb300..00000000
--- a/bindings/nodejs/examples/presign.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-const http = require('node:http')
-const url = require('node:url')
-const { Operator } = require('../index')
-
-const op = new Operator('s3', {
-  root: '/',
-  bucket: 'example-bucket',
-})
-
-const server = http.createServer(async (req, res) => {
-  res.setHeader('Content-Type', 'text/json; charset=utf-8')
-
-  if (req.url.startsWith('/presign') && req.method === 'GET') {
-    const urlParts = url.parse(req.url, true)
-    const path = urlParts.query.path
-    const expires = urlParts.query.expires
-
-    const presignedRequest = op.presignRead(path, parseInt(expires))
-
-    res.statusCode = 200
-    res.end(JSON.stringify(presignedRequest))
-  } else {
-    res.statusCode = 404
-    res.end('Not Found')
-  }
-})
-
-server.listen(3000, () => {
-  console.log('Server is listening on port 3000.')
-})
diff --git a/bindings/nodejs/index.d.ts b/bindings/nodejs/index.d.ts
index fd56c055..502cd630 100644
--- a/bindings/nodejs/index.d.ts
+++ b/bindings/nodejs/index.d.ts
@@ -32,36 +32,237 @@ export interface PresignedRequest {
 }
 export class Operator {
   constructor(scheme: string, options?: Record<string, string> | undefined | null)
-  /** Get current path's metadata **without cache** directly. */
+  /**
+   * Get current path's metadata **without cache** directly.
+   *
+   * ### Notes
+   * Use stat if you:
+   *
+   * - Want detect the outside changes of path.
+   * - Don’t want to read from cached metadata.
+   *
+   * You may want to use `metadata` if you are working with entries returned by `Lister`. It’s highly possible that metadata you want has already been cached.
+   *
+   * ### Example
+   * ```javascript
+   * const meta = await op.stat("test");
+   * if (meta.isDir) {
+   *   // do something
+   * }
+   * ```
+   */
   stat(path: string): Promise<Metadata>
-  /** Get current path's metadata **without cache** directly and synchronously. */
+  /**
+   * Get current path's metadata **without cache** directly and synchronously.
+   *
+   * ### Example
+   * ```javascript
+   * const meta = op.statSync("test");
+   * if (meta.isDir) {
+   *   // do something
+   * }
+   * ```
+   */
   statSync(path: string): Metadata
-  /** Create dir with given path. */
+  /**
+   * Check if this operator can work correctly.
+   *
+   * We will send a `list` request to path and return any errors we met.
+   *
+   * ### Example
+   * ```javascript
+   * await op.check();
+   * ```
+   */
+  check(): Promise<void>
+  /**
+   * Check if this path exists or not.
+   *
+   * ### Example
+   * ```javascript
+   * await op.isExist("test");
+   * ```
+   */
+  isExist(path: string): Promise<boolean>
+  /**
+   * Check if this path exists or not synchronously.
+   *
+   * ### Example
+   * ```javascript
+   * op.isExistSync("test");
+   * ```
+   */
+  isExistSync(path: string): boolean
+  /**
+   * Create dir with given path.
+   *
+   * ### Example
+   * ```javascript
+   * await op.createDir("path/to/dir/");
+   * ```
+   */
   createDir(path: string): Promise<void>
-  /** Create dir with given path synchronously. */
+  /**
+   * Create dir with given path synchronously.
+   *
+   * ### Example
+   * ```javascript
+   * op.createDirSync("path/to/dir/");
+   * ```
+   */
   createDirSync(path: string): void
-  /** Write bytes into path. */
+  /**
+   * Write bytes into path.
+   *
+   * ### Example
+   * ```javascript
+   * await op.write("path/to/file", Buffer.from("hello world"));
+   * // or
+   * await op.write("path/to/file", "hello world");
+   * ```
+   */
   write(path: string, content: Buffer | string): Promise<void>
-  /** Write bytes into path synchronously. */
+  /**
+   * Write bytes into path synchronously.
+   *
+   * ### Example
+   * ```javascript
+   * op.writeSync("path/to/file", Buffer.from("hello world"));
+   * // or
+   * op.writeSync("path/to/file", "hello world");
+   * ```
+   */
   writeSync(path: string, content: Buffer | string): void
-  /** Read the whole path into a buffer. */
+  /**
+   * Read the whole path into a buffer.
+   *
+   * ### Example
+   * ```javascript
+   * const buf = await op.read("path/to/file");
+   * ```
+   */
   read(path: string): Promise<Buffer>
-  /** Read the whole path into a buffer synchronously. */
+  /**
+   * Read the whole path into a buffer synchronously.
+   *
+   * ### Example
+   * ```javascript
+   * const buf = op.readSync("path/to/file");
+   * ```
+   */
   readSync(path: string): Buffer
-  /** List dir in flat way. */
+  /**
+   * List dir in flat way.
+   *
+   * This function will create a new handle to list entries.
+   *
+   * An error will be returned if given path doesn’t end with /.
+   *
+   * ### Example
+   * ```javascript
+   * const lister = await op.scan("/path/to/dir/");
+   * while (true)) {
+   *   const entry = await lister.next();
+   *   if (entry === null) {
+   *     break;
+   *   }
+   *   let meta = await op.stat(entry.path);
+   *   if (meta.is_file) {
+   *     // do something
+   *   }
+   * }
+   * `````
+   */
   scan(path: string): Promise<Lister>
-  /** List dir in flat way synchronously. */
+  /**
+   * List dir in flat way synchronously.
+   *
+   * This function will create a new handle to list entries.
+   *
+   * An error will be returned if given path doesn’t end with /.
+   *
+   * ### Example
+   * ```javascript
+   * const lister = op.scan_sync(/path/to/dir/");
+   * while (true)) {
+   *   const entry = lister.next();
+   *   if (entry === null) {
+   *     break;
+   *   }
+   *   let meta = op.statSync(entry.path);
+   *   if (meta.is_file) {
+   *     // do something
+   *   }
+   * }
+   * `````
+   */
   scanSync(path: string): BlockingLister
-  /** Delete the given path. */
+  /**
+   * Delete the given path.
+   *
+   * ### Notes
+   * Delete not existing error won’t return errors.
+   *
+   * ### Example
+   * ```javascript
+   * await op.delete("test");
+   * ```
+   */
   delete(path: string): Promise<void>
-  /** Delete the given path synchronously. */
+  /**
+   * Delete the given path synchronously.
+   *
+   * ### Example
+   * ```javascript
+   * op.deleteSync("test");
+   * ```
+   */
   deleteSync(path: string): void
+  /**
+   * Remove given paths.
+   *
+   * ### Notes
+   * If underlying services support delete in batch, we will use batch delete instead.
+   *
+   * ### Examples
+   * ```javascript
+   * await op.remove(["abc", "def"]);
+   * ```
+   */
+  remove(paths: Array<string>): Promise<void>
+  /**
+   * Remove the path and all nested dirs and files recursively.
+   *
+   * ### Notes
+   * If underlying services support delete in batch, we will use batch delete instead.
+   *
+   * ### Examples
+   * ```javascript
+   * await op.removeAll("path/to/dir/");
+   * ```
+   */
+  removeAll(path: string): Promise<void>
   /**
    * List given path.
    *
    * This function will create a new handle to list entries.
    *
    * An error will be returned if given path doesn't end with `/`.
+   *
+   * ### Example
+   * ```javascript
+   * const lister = await op.list("path/to/dir/");
+   * while (true)) {
+   *   const entry = await lister.next();
+   *   if (entry === null) {
+   *     break;
+   *   }
+   *   let meta = await op.stat(entry.path);
+   *   if (meta.isFile) {
+   *     // do something
+   *   }
+   * }
+   * ```
    */
   list(path: string): Promise<Lister>
   /**
@@ -70,24 +271,69 @@ export class Operator {
    * This function will create a new handle to list entries.
    *
    * An error will be returned if given path doesn't end with `/`.
+   *
+   * ### Example
+   * ```javascript
+   * const lister = op.listSync("path/to/dir/");
+   * while (true)) {
+   *   const entry = lister.next();
+   *   if (entry === null) {
+   *     break;
+   *   }
+   *   let meta = op.statSync(entry.path);
+   *   if (meta.isFile) {
+   *     // do something
+   *   }
+   * }
+   * ```
    */
   listSync(path: string): BlockingLister
   /**
    * Get a presigned request for read.
    *
    * Unit of expires is seconds.
+   *
+   * ### Example
+   *
+   * ```javascript
+   * const req = op.presignRead(path, parseInt(expires));
+   *
+   * console.log("method: ", req.method)
+   * console.log("url: ", req.url)
+   * console.log("headers: ", req.headers)
+   * ```
    */
   presignRead(path: string, expires: number): PresignedRequest
   /**
    * Get a presigned request for write.
    *
    * Unit of expires is seconds.
+   *
+   * ### Example
+   *
+   * ```javascript
+   * const req = op.presignWrite(path, parseInt(expires));
+   *
+   * console.log("method: ", req.method)
+   * console.log("url: ", req.url)
+   * console.log("headers: ", req.headers)
+   * ```
    */
   presignWrite(path: string, expires: number): PresignedRequest
   /**
    * Get a presigned request for stat.
    *
    * Unit of expires is seconds.
+   *
+   * ### Example
+   *
+   * ```javascript
+   * const req = op.presignStat(path, parseInt(expires));
+   *
+   * console.log("method: ", req.method)
+   * console.log("url: ", req.url)
+   * console.log("headers: ", req.headers)
+   * ```
    */
   presignStat(path: string, expires: number): PresignedRequest
 }
diff --git a/bindings/nodejs/package.json b/bindings/nodejs/package.json
index 798dd208..db8fbdc6 100644
--- a/bindings/nodejs/package.json
+++ b/bindings/nodejs/package.json
@@ -49,7 +49,7 @@
     "@swc/core": "^1.3.38",
     "@types/node": "^18.14.5",
     "prettier": "^2.8.4",
-    "typedoc": "^0.23.26",
+    "typedoc": "^0.23.28",
     "typescript": "^5.0.2"
   },
   "engines": {
diff --git a/bindings/nodejs/src/lib.rs b/bindings/nodejs/src/lib.rs
index f3178906..d95c7aa2 100644
--- a/bindings/nodejs/src/lib.rs
+++ b/bindings/nodejs/src/lib.rs
@@ -102,6 +102,22 @@ impl Operator {
     }
 
     /// Get current path's metadata **without cache** directly.
+    ///
+    /// ### Notes
+    /// Use stat if you:
+    ///
+    /// - Want detect the outside changes of path.
+    /// - Don’t want to read from cached metadata.
+    ///
+    /// You may want to use `metadata` if you are working with entries returned by `Lister`. It’s highly possible that metadata you want has already been cached.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// const meta = await op.stat("test");
+    /// if (meta.isDir) {
+    ///   // do something
+    /// }
+    /// ```
     #[napi]
     pub async fn stat(&self, path: String) -> Result<Metadata> {
         let meta = self.0.stat(&path).await.map_err(format_napi_error)?;
@@ -110,6 +126,14 @@ impl Operator {
     }
 
     /// Get current path's metadata **without cache** directly and synchronously.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// const meta = op.statSync("test");
+    /// if (meta.isDir) {
+    ///   // do something
+    /// }
+    /// ```
     #[napi]
     pub fn stat_sync(&self, path: String) -> Result<Metadata> {
         let meta = self.0.blocking().stat(&path).map_err(format_napi_error)?;
@@ -117,13 +141,58 @@ impl Operator {
         Ok(Metadata(meta))
     }
 
+    /// Check if this operator can work correctly.
+    ///
+    /// We will send a `list` request to path and return any errors we met.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// await op.check();
+    /// ```
+    #[napi]
+    pub async fn check(&self) -> Result<()> {
+        self.0.check().await.map_err(format_napi_error)
+    }
+
+    /// Check if this path exists or not.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// await op.isExist("test");
+    /// ```
+    #[napi]
+    pub async fn is_exist(&self, path: String) -> Result<bool> {
+        self.0.is_exist(&path).await.map_err(format_napi_error)
+    }
+
+    /// Check if this path exists or not synchronously.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// op.isExistSync("test");
+    /// ```
+    #[napi]
+    pub fn is_exist_sync(&self, path: String) -> Result<bool> {
+        self.0.blocking().is_exist(&path).map_err(format_napi_error)
+    }
+
     /// Create dir with given path.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// await op.createDir("path/to/dir/");
+    /// ```
     #[napi]
     pub async fn create_dir(&self, path: String) -> Result<()> {
         self.0.create_dir(&path).await.map_err(format_napi_error)
     }
 
     /// Create dir with given path synchronously.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// op.createDirSync("path/to/dir/");
+    /// ```
     #[napi]
     pub fn create_dir_sync(&self, path: String) -> Result<()> {
         self.0
@@ -133,20 +202,45 @@ impl Operator {
     }
 
     /// Write bytes into path.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// await op.write("path/to/file", Buffer.from("hello world"));
+    /// // or
+    /// await op.write("path/to/file", "hello world");
+    /// ```
     #[napi]
     pub async fn write(&self, path: String, content: Either<Buffer, String>) -> Result<()> {
-        let c = content.as_ref().to_owned();
+        let c = match content {
+            Either::A(buf) => buf.as_ref().to_owned(),
+            Either::B(s) => s.into_bytes(),
+        };
         self.0.write(&path, c).await.map_err(format_napi_error)
     }
 
     /// Write bytes into path synchronously.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// op.writeSync("path/to/file", Buffer.from("hello world"));
+    /// // or
+    /// op.writeSync("path/to/file", "hello world");
+    /// ```
     #[napi]
     pub fn write_sync(&self, path: String, content: Either<Buffer, String>) -> Result<()> {
-        let c = content.as_ref().to_owned();
+        let c = match content {
+            Either::A(buf) => buf.as_ref().to_owned(),
+            Either::B(s) => s.into_bytes(),
+        };
         self.0.blocking().write(&path, c).map_err(format_napi_error)
     }
 
     /// Read the whole path into a buffer.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// const buf = await op.read("path/to/file");
+    /// ```
     #[napi]
     pub async fn read(&self, path: String) -> Result<Buffer> {
         let res = self.0.read(&path).await.map_err(format_napi_error)?;
@@ -154,6 +248,11 @@ impl Operator {
     }
 
     /// Read the whole path into a buffer synchronously.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// const buf = op.readSync("path/to/file");
+    /// ```
     #[napi]
     pub fn read_sync(&self, path: String) -> Result<Buffer> {
         let res = self.0.blocking().read(&path).map_err(format_napi_error)?;
@@ -161,12 +260,50 @@ impl Operator {
     }
 
     /// List dir in flat way.
+    ///
+    /// This function will create a new handle to list entries.
+    ///
+    /// An error will be returned if given path doesn’t end with /.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// const lister = await op.scan("/path/to/dir/");
+    /// while (true)) {
+    ///   const entry = await lister.next();
+    ///   if (entry === null) {
+    ///     break;
+    ///   }
+    ///   let meta = await op.stat(entry.path);
+    ///   if (meta.is_file) {
+    ///     // do something
+    ///   }
+    /// }
+    /// `````
     #[napi]
     pub async fn scan(&self, path: String) -> Result<Lister> {
         Ok(Lister(self.0.scan(&path).await.map_err(format_napi_error)?))
     }
 
     /// List dir in flat way synchronously.
+    ///
+    /// This function will create a new handle to list entries.
+    ///
+    /// An error will be returned if given path doesn’t end with /.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// const lister = op.scan_sync(/path/to/dir/");
+    /// while (true)) {
+    ///   const entry = lister.next();
+    ///   if (entry === null) {
+    ///     break;
+    ///   }
+    ///   let meta = op.statSync(entry.path);
+    ///   if (meta.is_file) {
+    ///     // do something
+    ///   }
+    /// }
+    /// `````
     #[napi]
     pub fn scan_sync(&self, path: String) -> Result<BlockingLister> {
         Ok(BlockingLister(
@@ -175,22 +312,78 @@ impl Operator {
     }
 
     /// Delete the given path.
+    ///
+    /// ### Notes
+    /// Delete not existing error won’t return errors.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// await op.delete("test");
+    /// ```
     #[napi]
     pub async fn delete(&self, path: String) -> Result<()> {
         self.0.delete(&path).await.map_err(format_napi_error)
     }
 
     /// Delete the given path synchronously.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// op.deleteSync("test");
+    /// ```
     #[napi]
     pub fn delete_sync(&self, path: String) -> Result<()> {
         self.0.blocking().delete(&path).map_err(format_napi_error)
     }
 
+    /// Remove given paths.
+    ///
+    /// ### Notes
+    /// If underlying services support delete in batch, we will use batch delete instead.
+    ///
+    /// ### Examples
+    /// ```javascript
+    /// await op.remove(["abc", "def"]);
+    /// ```
+    #[napi]
+    pub async fn remove(&self, paths: Vec<String>) -> Result<()> {
+        self.0.remove(paths).await.map_err(format_napi_error)
+    }
+
+    /// Remove the path and all nested dirs and files recursively.
+    ///
+    /// ### Notes
+    /// If underlying services support delete in batch, we will use batch delete instead.
+    ///
+    /// ### Examples
+    /// ```javascript
+    /// await op.removeAll("path/to/dir/");
+    /// ```
+    #[napi]
+    pub async fn remove_all(&self, path: String) -> Result<()> {
+        self.0.remove_all(&path).await.map_err(format_napi_error)
+    }
+
     /// List given path.
     ///
     /// This function will create a new handle to list entries.
     ///
     /// An error will be returned if given path doesn't end with `/`.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// const lister = await op.list("path/to/dir/");
+    /// while (true)) {
+    ///   const entry = await lister.next();
+    ///   if (entry === null) {
+    ///     break;
+    ///   }
+    ///   let meta = await op.stat(entry.path);
+    ///   if (meta.isFile) {
+    ///     // do something
+    ///   }
+    /// }
+    /// ```
     #[napi]
     pub async fn list(&self, path: String) -> Result<Lister> {
         Ok(Lister(self.0.list(&path).await.map_err(format_napi_error)?))
@@ -201,6 +394,21 @@ impl Operator {
     /// This function will create a new handle to list entries.
     ///
     /// An error will be returned if given path doesn't end with `/`.
+    ///
+    /// ### Example
+    /// ```javascript
+    /// const lister = op.listSync("path/to/dir/");
+    /// while (true)) {
+    ///   const entry = lister.next();
+    ///   if (entry === null) {
+    ///     break;
+    ///   }
+    ///   let meta = op.statSync(entry.path);
+    ///   if (meta.isFile) {
+    ///     // do something
+    ///   }
+    /// }
+    /// ```
     #[napi]
     pub fn list_sync(&self, path: String) -> Result<BlockingLister> {
         Ok(BlockingLister(
@@ -211,6 +419,16 @@ impl Operator {
     /// Get a presigned request for read.
     ///
     /// Unit of expires is seconds.
+    ///
+    /// ### Example
+    ///
+    /// ```javascript
+    /// const req = op.presignRead(path, parseInt(expires));
+    ///
+    /// console.log("method: ", req.method);
+    /// console.log("url: ", req.url);
+    /// console.log("headers: ", req.headers);
+    /// ```
     #[napi]
     pub fn presign_read(&self, path: String, expires: u32) -> Result<PresignedRequest> {
         let res = self
@@ -223,6 +441,16 @@ impl Operator {
     /// Get a presigned request for write.
     ///
     /// Unit of expires is seconds.
+    ///
+    /// ### Example
+    ///
+    /// ```javascript
+    /// const req = op.presignWrite(path, parseInt(expires));
+    ///
+    /// console.log("method: ", req.method);
+    /// console.log("url: ", req.url);
+    /// console.log("headers: ", req.headers);
+    /// ```
     #[napi]
     pub fn presign_write(&self, path: String, expires: u32) -> Result<PresignedRequest> {
         let res = self
@@ -235,6 +463,16 @@ impl Operator {
     /// Get a presigned request for stat.
     ///
     /// Unit of expires is seconds.
+    ///
+    /// ### Example
+    ///
+    /// ```javascript
+    /// const req = op.presignStat(path, parseInt(expires));
+    ///
+    /// console.log("method: ", req.method);
+    /// console.log("url: ", req.url);
+    /// console.log("headers: ", req.headers);
+    /// ```
     #[napi]
     pub fn presign_stat(&self, path: String, expires: u32) -> Result<PresignedRequest> {
         let res = self
diff --git a/bindings/nodejs/yarn.lock b/bindings/nodejs/yarn.lock
index 26ef0884..9914c06a 100644
--- a/bindings/nodejs/yarn.lock
+++ b/bindings/nodejs/yarn.lock
@@ -883,7 +883,7 @@ __metadata:
     "@swc/core": ^1.3.38
     "@types/node": ^18.14.5
     prettier: ^2.8.4
-    typedoc: ^0.23.26
+    typedoc: ^0.23.28
     typescript: ^5.0.2
   languageName: unknown
   linkType: soft
@@ -1140,19 +1140,19 @@ __metadata:
   languageName: node
   linkType: hard
 
-"typedoc@npm:^0.23.26":
-  version: 0.23.26
-  resolution: "typedoc@npm:0.23.26"
+"typedoc@npm:^0.23.28":
+  version: 0.23.28
+  resolution: "typedoc@npm:0.23.28"
   dependencies:
     lunr: ^2.3.9
     marked: ^4.2.12
     minimatch: ^7.1.3
     shiki: ^0.14.1
   peerDependencies:
-    typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x
+    typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x
   bin:
     typedoc: bin/typedoc
-  checksum: 09dbd221b5bd27a7f6c593a6aa7e4efc3c46f20761e109a76bf0ed7239011cca1261357094710c01472582060d75a7558aab5bf5b78db3aff7c52188d146ee65
+  checksum: 40eb4e207aac1b734e09400cf03f543642cc7b11000895198dd5a0d3166315759ccf4ac30a2915153597c5c186101c72bac2f1fc12b428184a9274d3a0e44c5e
   languageName: node
   linkType: hard