diff --git a/packages/create-lz-oapp/package.json b/packages/create-lz-oapp/package.json
index e3192671b..ea46d038d 100644
--- a/packages/create-lz-oapp/package.json
+++ b/packages/create-lz-oapp/package.json
@@ -33,6 +33,7 @@
"yoga-wasm-web": "~0.3.3"
},
"devDependencies": {
+ "@layerzerolabs/io-utils": "~0.0.1",
"@tanstack/react-query": "^5.8.4",
"@types/mocha": "^10.0.6",
"@types/prompts": "^2.4.9",
diff --git a/packages/create-lz-oapp/src/utilities/filesystem.ts b/packages/create-lz-oapp/src/utilities/filesystem.ts
deleted file mode 100644
index f6ef1f54e..000000000
--- a/packages/create-lz-oapp/src/utilities/filesystem.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { lstatSync } from 'fs'
-
-export const isDirectory = (path: string) => {
- try {
- return lstatSync(path).isDirectory()
- } catch {
- return false
- }
-}
diff --git a/packages/create-lz-oapp/src/utilities/prompts.ts b/packages/create-lz-oapp/src/utilities/prompts.ts
index 7d34624c2..8c1daaaf2 100644
--- a/packages/create-lz-oapp/src/utilities/prompts.ts
+++ b/packages/create-lz-oapp/src/utilities/prompts.ts
@@ -1,7 +1,7 @@
import { EXAMPLES, PACKAGE_MANAGERS } from '@/config.js'
import prompts from 'prompts'
import { isPackageManagerAvailable } from './installation.js'
-import { isDirectory } from './filesystem.js'
+import { isDirectory } from '@layerzerolabs/io-utils'
import { resolve } from 'path'
const handlePromptState = (state: { aborted: boolean }) => {
diff --git a/packages/io-utils/.eslintignore b/packages/io-utils/.eslintignore
new file mode 100644
index 000000000..0f295f243
--- /dev/null
+++ b/packages/io-utils/.eslintignore
@@ -0,0 +1,3 @@
+.turbo
+dist
+node_modules
\ No newline at end of file
diff --git a/packages/io-utils/.eslintrc.json b/packages/io-utils/.eslintrc.json
new file mode 100644
index 000000000..be97c53fb
--- /dev/null
+++ b/packages/io-utils/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../../.eslintrc.json"
+}
diff --git a/packages/io-utils/README.md b/packages/io-utils/README.md
new file mode 100644
index 000000000..11a8fdc68
--- /dev/null
+++ b/packages/io-utils/README.md
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+@layerzerolabs/io-utils
+
+
+
+
+
+
+
+
+
+
+
+## Installation
+
+```bash
+pnpm install @layerzerolabs/io-utils
+```
+
+```bash
+yarn install @layerzerolabs/io-utils
+```
+
+```bash
+npm install @layerzerolabs/io-utils
+```
+
+## API Documentation
+
+### Filesystem utilities
+
+#### isDirectory(path)
+
+Returns `true` if specified filesystem `path` points to a directory, `false` otherwise. Does not throw if `path` does not exist on the filesystem, instead returns `false`
+
+#### isFile(path)
+
+Returns `true` if specified filesystem `path` points to a file, `false` otherwise. Does not throw if `path` does not exist on the filesystem, instead returns `false`
+
+#### isReadable(path)
+
+Returns `true` if specified filesystem `path` can be read by the current user, `false` otherwise. Does not throw if `path` does not exist on the filesystem, instead returns `false`
diff --git a/packages/io-utils/jest.config.js b/packages/io-utils/jest.config.js
new file mode 100644
index 000000000..16148cfb1
--- /dev/null
+++ b/packages/io-utils/jest.config.js
@@ -0,0 +1,8 @@
+/** @type {import('ts-jest').JestConfigWithTsJest} */
+module.exports = {
+ preset: 'ts-jest',
+ testEnvironment: 'node',
+ moduleNameMapper: {
+ '^@/(.*)$': '/src/$1',
+ },
+};
diff --git a/packages/io-utils/package.json b/packages/io-utils/package.json
new file mode 100644
index 000000000..6423fb388
--- /dev/null
+++ b/packages/io-utils/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "@layerzerolabs/io-utils",
+ "version": "0.0.1",
+ "private": true,
+ "description": "Utilities for working with I/O in LayerZero utils",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/LayerZero-Labs/lz-utils.git",
+ "directory": "packages/io-utils"
+ },
+ "license": "MIT",
+ "exports": {
+ ".": {
+ "types": "./dist/index.d.ts",
+ "require": "./dist/index.js",
+ "import": "./dist/index.mjs"
+ }
+ },
+ "main": "dist/index.js",
+ "module": "dist/index.mjs",
+ "types": "dist/index.d.ts",
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "prebuild": "tsc -noEmit",
+ "build": "npx tsup",
+ "clean": "rm -rf dist",
+ "lint": "npx eslint '**/*.{js,ts,json}'",
+ "test": "jest --passWithNoTests"
+ },
+ "devDependencies": {
+ "@types/jest": "^29.5.10",
+ "fast-check": "^3.14.0",
+ "jest": "^29.7.0",
+ "ts-jest": "^29.1.1",
+ "ts-node": "^10.9.1",
+ "tslib": "~2.6.2",
+ "tsup": "~8.0.1",
+ "typescript": "^5.2.2"
+ }
+}
\ No newline at end of file
diff --git a/packages/io-utils/src/filesystem/filesystem.ts b/packages/io-utils/src/filesystem/filesystem.ts
new file mode 100644
index 000000000..fa36df40f
--- /dev/null
+++ b/packages/io-utils/src/filesystem/filesystem.ts
@@ -0,0 +1,25 @@
+import { accessSync, constants, lstatSync } from 'fs'
+
+export const isDirectory = (path: string): boolean => {
+ try {
+ return lstatSync(path).isDirectory()
+ } catch {
+ return false
+ }
+}
+
+export const isFile = (path: string): boolean => {
+ try {
+ return lstatSync(path).isFile()
+ } catch {
+ return false
+ }
+}
+
+export const isReadable = (path: string): boolean => {
+ try {
+ return accessSync(path, constants.R_OK), true
+ } catch {
+ return false
+ }
+}
diff --git a/packages/io-utils/src/filesystem/index.ts b/packages/io-utils/src/filesystem/index.ts
new file mode 100644
index 000000000..b0899e4ef
--- /dev/null
+++ b/packages/io-utils/src/filesystem/index.ts
@@ -0,0 +1 @@
+export * from './filesystem'
diff --git a/packages/io-utils/src/index.ts b/packages/io-utils/src/index.ts
new file mode 100644
index 000000000..b0899e4ef
--- /dev/null
+++ b/packages/io-utils/src/index.ts
@@ -0,0 +1 @@
+export * from './filesystem'
diff --git a/packages/io-utils/tsconfig.json b/packages/io-utils/tsconfig.json
new file mode 100644
index 000000000..f083b2ecb
--- /dev/null
+++ b/packages/io-utils/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "../../tsconfig.json",
+ "exclude": ["dist", "node_modules"],
+ "include": ["src", "test"],
+ "compilerOptions": {
+ "types": ["node", "jest"],
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ }
+}
diff --git a/packages/io-utils/tsup.config.ts b/packages/io-utils/tsup.config.ts
new file mode 100644
index 000000000..b0e373950
--- /dev/null
+++ b/packages/io-utils/tsup.config.ts
@@ -0,0 +1,12 @@
+import { defineConfig } from 'tsup'
+
+export default defineConfig({
+ entry: ['src/index.ts'],
+ outDir: './dist',
+ clean: true,
+ dts: true,
+ sourcemap: true,
+ splitting: false,
+ treeshake: true,
+ format: ['esm', 'cjs'],
+})