diff --git a/README.md b/README.md
index 4435fef..2a32093 100644
--- a/README.md
+++ b/README.md
@@ -88,9 +88,18 @@ pdfkit.loadZga(globalThis);
 ```
 npm install zgapdfsigner
 ```
+If using [typescript](https://www.typescriptlang.org/) for development, installation of [definitely typed for node-forge](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node-forge) is necessary.
+```
+npm install --save-dev @types/node-forge
+```
 2. Import
 ```js
+// CommonJS Mode
 const Zga = require("zgapdfsigner");
+// ES Module Mode
+import { default as Zga } from "zgapdfsigner";
+// Typescript
+import * as Zga from "zgapdfsigner";
 ```
 
 ## Let's sign
diff --git a/lib/zganode.d.ts b/lib/zganode.d.ts
new file mode 100644
index 0000000..e602ccb
--- /dev/null
+++ b/lib/zganode.d.ts
@@ -0,0 +1,111 @@
+import * as forge from "node-forge";
+import * as PDFLib from "pdf-lib";
+export * as forge from "node-forge";
+export * as PDFLib from "pdf-lib";
+
+export declare function u8arrToRaw(uarr: Uint8Array): string;
+export declare function rawToU8arr(raw: string): Uint8Array;
+export declare namespace Crypto {
+  enum Mode {
+    RC4_40,
+    RC4_128,
+    AES_128,
+    AES_256,
+  }
+}
+export type DSSInfo = {
+  certs?: Array<forge.pki.Certificate>;
+  ocsps?: Array<Uint8Array>;
+  crls?: Array<Uint8Array>;
+};
+export type EncryptOption = {
+  mode: Crypto.Mode;
+  permissions?: Array<string>;
+  userpwd?: string;
+  ownerpwd?: string;
+  pubkeys?: Array<PubKeyInfo>;
+};
+export type PubKeyInfo = {
+  c?: Array<number> | Uint8Array | ArrayBuffer | string | forge.pki.Certificate;
+  p?: Array<string>;
+};
+export type SignAreaInfo = {
+  x: number;
+  y: number;
+  w?: number;
+  h?: number;
+};
+export type SignTextInfo = {
+  text: string,
+  fontData?: Array<number> | Uint8Array | ArrayBuffer | string;
+  color?: string;
+  opacity?: number;
+  blendMode?: string;
+  lineHeight?: number;
+  size: number,
+  xOffset?: number;
+  yOffset?: number;
+  wMax?: number;
+  align?: number;
+  noBreaks?: string;
+};
+export type SignImageInfo = {
+  imgData: Array<number> | Uint8Array | ArrayBuffer | string;
+  imgType: string;
+  opacity?: number;
+  blendMode?: string;
+};
+export type SignDrawInfo = {
+  area: SignAreaInfo;
+  pageidx?: number | string;
+  /** @deprecated use imgInfo instead */
+  imgData?: Array<number> | Uint8Array | ArrayBuffer | string;
+  /** @deprecated use imgInfo instead */
+  imgType?: string;
+  imgInfo?: SignImageInfo;
+  textInfo?: SignTextInfo;
+};
+export type SignOption = {
+  p12cert?: Array<number> | Uint8Array | ArrayBuffer | string;
+  pwd?: string;
+  permission?: number;
+  reason?: string;
+  location?: string;
+  contact?: string;
+  signdate?: Date | TsaServiceInfo | string;
+  signame?: string;
+  drawinf?: SignDrawInfo;
+  ltv?: number;
+  debug?: boolean;
+};
+export type TsaServiceInfo = {
+  url: string;
+  len?: number;
+  headers?: Record<string, any>;
+};
+
+export declare class CertsChain {
+  constructor(certs?: Array<forge.pki.Certificate | forge.asn1.Asn1 | string>);
+  buildChain(cert: forge.pki.Certificate): Promise<boolean>;
+  getAllCerts(): Array<forge.pki.Certificate>;
+  getSignCert(): forge.pki.Certificate;
+  isSelfSignedCert(): boolean;
+  prepareDSSInf(crlOnly?: boolean): Promise<DSSInfo>;
+}
+export declare class PdfCryptor {
+  constructor(encopt: EncryptOption);
+  encryptPdf(pdf: PDFLib.PDFDocument | Array<number> | Uint8Array | ArrayBuffer | string, ref?: PDFLib.PDFRef): Promise<PDFLib.PDFDocument>;
+  encryptObject(num: number, val: PDFLib.PDFObject): void;
+}
+export declare class PdfSigner {
+  constructor(signopt: SignOption);
+  sign(pdf: PDFLib.PDFDocument | Array<number> | Uint8Array | ArrayBuffer | string, cypopt?: EncryptOption): Promise<Uint8Array>;
+}
+export declare class TsaFetcher {
+  constructor(inf: TsaServiceInfo);
+  url: string;
+  len: number;
+  getCertsChain(): CertsChain;
+  getToken(forP7?: boolean): forge.asn1.Asn1;
+  queryTsa(data?: string): Promise<string>;
+}
diff --git a/package.json b/package.json
index 68e4fcf..54010aa 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "zgapdfsigner",
-  "version": "2.6.0",
+  "version": "2.7.0",
   "author": "zboris12",
   "description": "A javascript tool to sign a pdf or set protection to a pdf in web browser, Google Apps Script and nodejs.",
   "homepage": "https://github.com/zboris12/zgapdfsigner",
@@ -16,6 +16,7 @@
   "main": "lib/zganode.js",
   "files": [
     "dist/*.min.js",
+    "lib/*.d.ts",
     "lib/*.js"
   ],
   "keywords": [
@@ -30,7 +31,7 @@
   ],
   "scripts": {
     "build": "./build.sh",
-    "test": "node test4node.js"
+    "test": "node test4node.js ${pfxpwd}"
   },
   "dependencies": {
     "@pdf-lib/fontkit": "^1.1.1",
diff --git a/test-ts/.vscode/settings.json b/test-ts/.vscode/settings.json
new file mode 100644
index 0000000..9dbba42
--- /dev/null
+++ b/test-ts/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+  "editor.tabSize": 2,
+  "editor.formatOnSave": true,
+  "files.eol": "\n"
+}
\ No newline at end of file
diff --git a/test-ts/package.json b/test-ts/package.json
new file mode 100644
index 0000000..5485ad7
--- /dev/null
+++ b/test-ts/package.json
@@ -0,0 +1,20 @@
+{
+  "name": "zgapdfsigner-test-ts",
+  "version": "1.0.0",
+  "author": "zboris12",
+  "description": "A typescript program to test zgapdfsigner.",
+  "private": false,
+  "license": "MIT",
+  "main": "index.js",
+  "scripts": {
+    "build": "tsc",
+    "test": "node test/index.js ${pfxpwd}"
+  },
+  "dependencies": {
+    "zgapdfsigner": "^2.7.0"
+  },
+  "devDependencies": {
+    "@types/node-forge": "^1.3.11",
+    "typescript": "~4.9"
+  }
+}
\ No newline at end of file
diff --git a/test-ts/src/index.ts b/test-ts/src/index.ts
new file mode 100644
index 0000000..e8d059f
--- /dev/null
+++ b/test-ts/src/index.ts
@@ -0,0 +1,144 @@
+import * as m_fs from "node:fs";
+import * as  m_path from "node:path";
+import * as Zga from "zgapdfsigner";
+
+const workpath = "./";
+
+async function sign_protect(pdfPath: string, pfxPath: string, ps: string, perm: number, imgPath?: string, txt?: string, fontPath?: string): Promise<string> {
+  let pdf: Buffer = m_fs.readFileSync(pdfPath);
+  let pfx: Buffer = m_fs.readFileSync(pfxPath);
+  let img: Buffer | undefined = undefined;
+  let imgType: string = "";
+  let font: Buffer | undefined = undefined;
+
+  if (perm == 1) {
+    console.log("\nTest signing pdf with full protection. (permission 1 and password encryption)");
+  } else {
+    console.log("\nTest signing pdf with permission " + perm);
+  }
+
+  if (imgPath) {
+    img = m_fs.readFileSync(imgPath);
+    imgType = m_path.extname(imgPath).slice(1);
+  }
+  if (fontPath) {
+    font = m_fs.readFileSync(fontPath);
+  }
+  let sopt: Zga.SignOption = {
+    p12cert: pfx,
+    pwd: ps,
+    permission: perm,
+    signdate: "1",
+    reason: "I have a test reason " + perm + ".",
+    location: "I am on the earth " + perm + ".",
+    contact: "zga" + perm + "@zga.com",
+    ltv: 1,
+    debug: true,
+  };
+  if (img || txt) {
+    sopt.drawinf = {
+      area: {
+        x: 25, // left
+        y: 50, // top
+        w: txt ? undefined : 60,
+        h: txt ? undefined : 100,
+      },
+      pageidx: "-",
+      imgInfo: img ? {
+        imgData: img,
+        imgType: imgType,
+      } : undefined,
+      textInfo: txt ? {
+        text: txt,
+        fontData: font,
+        color: "00f0f1",
+        lineHeight: 20,
+        size: 16,
+        align: 1,
+        wMax: 80,
+        yOffset: 10,
+        xOffset: 20,
+        noBreaks: "[あいうえおA-Za-z0-9]",
+      } : undefined,
+    };
+  }
+
+  let eopt: Zga.EncryptOption | undefined = undefined;
+  if (perm == 1) {
+    eopt = {
+      mode: Zga.Crypto.Mode.AES_256,
+      permissions: ["copy", "copy-extract", "print-high"],
+      userpwd: "123",
+    };
+  }
+
+  let ser: Zga.PdfSigner = new Zga.PdfSigner(sopt);
+  let u8dat: Uint8Array = await ser.sign(pdf, eopt);
+  let outPath: string = "";
+  if (u8dat) {
+    outPath = m_path.join(__dirname, workpath + "test_perm" + perm + m_path.basename(pdfPath));
+    m_fs.writeFileSync(outPath, u8dat);
+    console.log("Output file: " + outPath);
+  }
+  return outPath;
+}
+
+async function addtsa(pdfPath: string): Promise<string> {
+  console.log("\nTest signing pdf by a timestamp.");
+
+  let pdf: Buffer = m_fs.readFileSync(pdfPath);
+  let sopt: Zga.SignOption = {
+    signdate: "2",
+    reason: "I have a test reason tsa.",
+    location: "I am on the earth tsa.",
+    contact: "zgatsa@zga.com",
+    ltv: 1,
+    debug: true,
+  };
+  let ser: Zga.PdfSigner = new Zga.PdfSigner(sopt);
+  let u8dat: Uint8Array = await ser.sign(pdf);
+  let outPath: string = m_path.join(__dirname, workpath + "tsa_" + m_path.basename(pdfPath));
+  m_fs.writeFileSync(outPath, u8dat);
+  console.log("Output file: " + outPath);
+  return outPath;
+}
+
+async function main1(angle: number): Promise<void> {
+  let pdfPath: string = m_path.join(__dirname, workpath + "_test" + (angle ? "_" + angle : "") + ".pdf");
+  let pfxPath: string = m_path.join(__dirname, workpath + "_test.pfx");
+  let ps: string = "";
+  let imgPath: string = m_path.join(__dirname, workpath + "_test.png");
+  let fontPath: string = m_path.join(__dirname, workpath + "_test.ttf");
+
+  if (process.argv.length > 3) {
+    pfxPath = process.argv[2];
+    ps = process.argv[3];
+  } else if (process.argv[2]) {
+    ps = process.argv[2];
+  }
+
+  if (!ps) {
+    // throw new Error("The passphrase is not specified.");
+    pfxPath = "";
+  }
+
+  if (pfxPath) {
+    await sign_protect(pdfPath, pfxPath, ps, 1, imgPath, "あいうえおあいうえおか\r\n\nThis is a test of text!\n", fontPath);
+    pdfPath = await sign_protect(pdfPath, pfxPath, ps, 2, undefined, "ありがとうご\r\n\nThis is an another test of text!\n", fontPath);
+    await addtsa(pdfPath);
+  } else {
+    await addtsa(pdfPath);
+  }
+
+  console.log("Done");
+}
+
+async function main(): Promise<void> {
+  let arr: Array<number> = [0, 90, 180, 270];
+  for (let i = 0; i < arr.length; i++) {
+    await main1(arr[i]);
+    // break;
+  }
+}
+
+main();
diff --git a/test-ts/tsconfig.json b/test-ts/tsconfig.json
new file mode 100644
index 0000000..cb0cc33
--- /dev/null
+++ b/test-ts/tsconfig.json
@@ -0,0 +1,24 @@
+{
+  "compilerOptions": {
+    "target": "es2015",
+    "module": "commonjs",
+    "newLine": "LF",
+    "declaration": true,
+    "sourceMap": true,
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "strict": true,
+    "noImplicitThis": true,
+    "rootDir": "./src",
+    "outDir": "./test",
+    "typeRoots": [
+      "node_modules/@types"
+    ]
+  },
+  "include": [
+    "src/**/*"
+  ],
+  "exclude": [
+    "node_modules"
+  ]
+}
\ No newline at end of file
diff --git a/test4node.js b/test4node.js
index 7e271bd..bb5fe8c 100644
--- a/test4node.js
+++ b/test4node.js
@@ -1,3 +1,10 @@
+// ES Module Mode
+// import * as m_fs from "node:fs";
+// import * as m_path from "node:path";
+// import { fileURLToPath } from "node:url";
+// import { default as Zga } from "./lib/zganode.js";
+// const __dirname = m_path.dirname(fileURLToPath(import.meta.url));
+
 const m_fs = require("fs");
 const m_path = require("path");
 const Zga = require("./lib/zganode.js");