From 2a0fa9ebf8eab172cb31693bc190dbc0c6ebdfd5 Mon Sep 17 00:00:00 2001 From: Prad Nukala Date: Wed, 7 Jan 2026 18:34:00 -0500 Subject: [PATCH] init(motr-enclave): Setup motr-enclave package --- bun.lock | 32 ++++++++ example/bun.lock | 132 ++++++++++++++++++++++++++++++ example/main.js | 150 ++++++++++++++++++++++++++++++++++ package.json | 32 ++++++++ scripts/build.ts | 30 +++++++ src/enclave.ts | 203 ++++++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 31 +++++++ src/tsconfig.json | 17 ++++ src/types.ts | 129 +++++++++++++++++++++++++++++ 9 files changed, 756 insertions(+) create mode 100644 bun.lock create mode 100644 example/bun.lock create mode 100644 example/main.js create mode 100644 package.json create mode 100644 scripts/build.ts create mode 100644 src/enclave.ts create mode 100644 src/index.ts create mode 100644 src/tsconfig.json create mode 100644 src/types.ts diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..794b047 --- /dev/null +++ b/bun.lock @@ -0,0 +1,32 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "@sonr/motr-enclave", + "dependencies": { + "@extism/extism": "^2.0.0-rc13", + }, + "devDependencies": { + "@types/bun": "latest", + "typescript": "^5.0.0", + }, + "peerDependencies": { + "@extism/extism": "^2.0.0-rc13", + }, + }, + }, + "packages": { + "@extism/extism": ["@extism/extism@2.0.0-rc13", "", {}, "sha512-iQ3mrPKOC0WMZ94fuJrKbJmMyz4LQ9Abf8gd4F5ShxKWa+cRKcVzk0EqRQsp5xXsQ2dO3zJTiA6eTc4Ihf7k+A=="], + + "@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="], + + "@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="], + + "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + } +} diff --git a/example/bun.lock b/example/bun.lock new file mode 100644 index 0000000..885e68b --- /dev/null +++ b/example/bun.lock @@ -0,0 +1,132 @@ +{ + "lockfileVersion": 1, + "configVersion": 0, + "workspaces": { + "": { + "name": "motr-enclave-example", + "dependencies": { + "@extism/extism": "^2.0.0-rc13", + }, + "devDependencies": { + "vite": "^5.4.0", + }, + }, + }, + "packages": { + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], + + "@extism/extism": ["@extism/extism@2.0.0-rc13", "", {}, "sha512-iQ3mrPKOC0WMZ94fuJrKbJmMyz4LQ9Abf8gd4F5ShxKWa+cRKcVzk0EqRQsp5xXsQ2dO3zJTiA6eTc4Ihf7k+A=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.55.1", "", { "os": "android", "cpu": "arm" }, "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.55.1", "", { "os": "android", "cpu": "arm64" }, "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.55.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.55.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.55.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.55.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.55.1", "", { "os": "linux", "cpu": "arm" }, "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.55.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.55.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.55.1", "", { "os": "linux", "cpu": "none" }, "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.55.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.55.1", "", { "os": "linux", "cpu": "x64" }, "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.55.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.55.1", "", { "os": "none", "cpu": "arm64" }, "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.55.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.55.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.55.1", "", { "os": "win32", "cpu": "x64" }, "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": "bin/esbuild" }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": "bin/nanoid.cjs" }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "rollup": ["rollup@4.55.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.55.1", "@rollup/rollup-android-arm64": "4.55.1", "@rollup/rollup-darwin-arm64": "4.55.1", "@rollup/rollup-darwin-x64": "4.55.1", "@rollup/rollup-freebsd-arm64": "4.55.1", "@rollup/rollup-freebsd-x64": "4.55.1", "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", "@rollup/rollup-linux-arm-musleabihf": "4.55.1", "@rollup/rollup-linux-arm64-gnu": "4.55.1", "@rollup/rollup-linux-arm64-musl": "4.55.1", "@rollup/rollup-linux-loong64-gnu": "4.55.1", "@rollup/rollup-linux-loong64-musl": "4.55.1", "@rollup/rollup-linux-ppc64-gnu": "4.55.1", "@rollup/rollup-linux-ppc64-musl": "4.55.1", "@rollup/rollup-linux-riscv64-gnu": "4.55.1", "@rollup/rollup-linux-riscv64-musl": "4.55.1", "@rollup/rollup-linux-s390x-gnu": "4.55.1", "@rollup/rollup-linux-x64-gnu": "4.55.1", "@rollup/rollup-linux-x64-musl": "4.55.1", "@rollup/rollup-openbsd-x64": "4.55.1", "@rollup/rollup-openharmony-arm64": "4.55.1", "@rollup/rollup-win32-arm64-msvc": "4.55.1", "@rollup/rollup-win32-ia32-msvc": "4.55.1", "@rollup/rollup-win32-x64-gnu": "4.55.1", "@rollup/rollup-win32-x64-msvc": "4.55.1", "fsevents": "~2.3.2" }, "bin": "dist/bin/rollup" }, "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "vite": ["vite@5.4.21", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": "bin/vite.js" }, "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw=="], + } +} diff --git a/example/main.js b/example/main.js new file mode 100644 index 0000000..17366cb --- /dev/null +++ b/example/main.js @@ -0,0 +1,150 @@ +import { createEnclave } from '../dist/enclave.js'; + +let enclave = null; +let lastDatabase = null; + +const LogLevel = { INFO: 'info', OK: 'ok', ERR: 'err', DATA: 'data' }; + +function log(level, method, message, data = null) { + const el = document.getElementById('log'); + const time = new Date().toISOString().slice(11, 23); + const prefix = method ? `[${method}]` : ''; + + let entry = `
${time} ${prefix} ${message}`; + if (data !== null) { + entry += `\n${JSON.stringify(data, null, 2)}`; + } + entry += '
'; + + el.innerHTML += entry; + el.scrollTop = el.scrollHeight; + + console.log(`[${time}] ${prefix} ${message}`, data ?? ''); +} + +function setStatus(ok, message) { + const el = document.getElementById('status'); + el.textContent = message; + el.className = `status ${ok ? 'ok' : 'err'}`; +} + +async function init() { + try { + log(LogLevel.INFO, null, 'Loading enclave.wasm...'); + enclave = await createEnclave('./enclave.wasm', { debug: true }); + setStatus(true, 'Ready'); + log(LogLevel.OK, null, 'Plugin loaded'); + } catch (err) { + setStatus(false, 'Failed'); + log(LogLevel.ERR, null, `Load failed: ${err.message}`); + } +} + +window.testGenerate = async function() { + if (!enclave) return log(LogLevel.ERR, 'generate', 'Plugin not loaded'); + + const credential = document.getElementById('credential').value; + log(LogLevel.INFO, 'generate', `credential=${credential.slice(0, 16)}...`); + + try { + const result = await enclave.generate(credential); + log(LogLevel.OK, 'generate', `DID created: ${result.did}`, result); + + if (result.database) { + lastDatabase = result.database; + document.getElementById('database').value = btoa(String.fromCharCode(...result.database)); + log(LogLevel.INFO, 'generate', 'Database saved for load() test'); + } + return result; + } catch (err) { + log(LogLevel.ERR, 'generate', err.message); + throw err; + } +}; + +window.testLoad = async function() { + if (!enclave) return log(LogLevel.ERR, 'load', 'Plugin not loaded'); + + const b64 = document.getElementById('database').value; + if (!b64) return log(LogLevel.ERR, 'load', 'Database required'); + + log(LogLevel.INFO, 'load', `database.length=${b64.length}`); + + try { + const database = Uint8Array.from(atob(b64), c => c.charCodeAt(0)); + const result = await enclave.load(database); + + if (result.success) { + log(LogLevel.OK, 'load', `Loaded DID: ${result.did}`, result); + } else { + log(LogLevel.ERR, 'load', result.error, result); + } + return result; + } catch (err) { + log(LogLevel.ERR, 'load', err.message); + throw err; + } +}; + +window.testExec = async function() { + if (!enclave) return log(LogLevel.ERR, 'exec', 'Plugin not loaded'); + + const filter = document.getElementById('filter').value; + if (!filter) return log(LogLevel.ERR, 'exec', 'Filter required'); + + log(LogLevel.INFO, 'exec', `filter="${filter}"`); + + try { + const result = await enclave.exec(filter); + + if (result.success) { + log(LogLevel.OK, 'exec', 'Success', result); + } else { + log(LogLevel.ERR, 'exec', result.error, result); + } + return result; + } catch (err) { + log(LogLevel.ERR, 'exec', err.message); + throw err; + } +}; + +window.testQuery = async function() { + if (!enclave) return log(LogLevel.ERR, 'query', 'Plugin not loaded'); + + const did = document.getElementById('did').value; + log(LogLevel.INFO, 'query', did ? `did="${did}"` : 'did=(current)'); + + try { + const result = await enclave.query(did); + log(LogLevel.OK, 'query', `Resolved: ${result.did}`, result); + return result; + } catch (err) { + log(LogLevel.ERR, 'query', err.message); + throw err; + } +}; + +window.setFilter = function(filter) { + document.getElementById('filter').value = filter; +}; + +window.clearLog = function() { + document.getElementById('log').innerHTML = ''; +}; + +window.runAllTests = async function() { + log(LogLevel.INFO, null, '=== Running all tests ==='); + + try { + await testGenerate(); + await testLoad(); + await testExec(); + await testQuery(); + log(LogLevel.OK, null, '=== All tests passed ==='); + } catch (err) { + log(LogLevel.ERR, null, `=== Tests failed: ${err.message} ===`); + } +}; + +init(); diff --git a/package.json b/package.json new file mode 100644 index 0000000..b52d5b6 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "@sonr/motr-enclave", + "version": "0.1.0", + "type": "module", + "main": "./dist/enclave.js", + "module": "./dist/enclave.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/enclave.js", + "types": "./dist/index.d.ts" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "bun run scripts/build.ts", + "typecheck": "tsc --noEmit -p src/tsconfig.json", + "clean": "rm -rf dist" + }, + "dependencies": { + "@extism/extism": "^2.0.0-rc13" + }, + "devDependencies": { + "@types/bun": "latest", + "typescript": "^5.0.0" + }, + "peerDependencies": { + "@extism/extism": "^2.0.0-rc13" + } +} diff --git a/scripts/build.ts b/scripts/build.ts new file mode 100644 index 0000000..4916b58 --- /dev/null +++ b/scripts/build.ts @@ -0,0 +1,30 @@ +import { $ } from 'bun'; + +const result = await Bun.build({ + entrypoints: ['./src/index.ts'], + outdir: './dist', + format: 'esm', + target: 'browser', + minify: false, + sourcemap: 'external', + external: ['@extism/extism'], + naming: { + entry: 'enclave.js', + }, +}); + +if (!result.success) { + console.error('Build failed:'); + for (const log of result.logs) { + console.error(log); + } + process.exit(1); +} + +console.log('Build successful:'); +for (const output of result.outputs) { + console.log(` ${output.path}`); +} + +await $`bun run tsc --emitDeclarationOnly --declaration -p src/tsconfig.json --outDir dist`; +console.log('Type declarations generated'); diff --git a/src/enclave.ts b/src/enclave.ts new file mode 100644 index 0000000..13bfb57 --- /dev/null +++ b/src/enclave.ts @@ -0,0 +1,203 @@ +import createPlugin, { type Plugin } from '@extism/extism'; +import type { + EnclaveOptions, + GenerateOutput, + LoadOutput, + ExecOutput, + QueryOutput, + Resource, +} from './types'; + +/** + * Motr Enclave - WebAssembly plugin wrapper for encrypted key storage + * + * @example + * ```typescript + * import { createEnclave } from '@sonr/motr-enclave'; + * + * const enclave = await createEnclave('/enclave.wasm'); + * const { did, database } = await enclave.generate(credential); + * ``` + */ +export class Enclave { + private plugin: Plugin; + private logger: EnclaveOptions['logger']; + private debug: boolean; + + private constructor(plugin: Plugin, options: EnclaveOptions = {}) { + this.plugin = plugin; + this.logger = options.logger ?? console; + this.debug = options.debug ?? false; + } + + /** + * Create an Enclave instance from a WASM source + * + * @param wasm - URL string, file path, or Uint8Array of WASM bytes + * @param options - Configuration options + */ + static async create( + wasm: string | Uint8Array, + options: EnclaveOptions = {} + ): Promise { + const manifest = + typeof wasm === 'string' + ? { wasm: [{ url: wasm }] } + : { wasm: [{ data: wasm }] }; + + const plugin = await createPlugin(manifest, { + useWasi: true, + logger: options.debug ? (options.logger as Console) : undefined, + }); + + return new Enclave(plugin, options); + } + + /** + * Initialize database with WebAuthn credential + * + * @param credential - Base64-encoded PublicKeyCredential from WebAuthn registration + * @returns DID and serialized database buffer + */ + async generate(credential: string): Promise { + this.log('generate: starting with credential'); + + const input = JSON.stringify({ credential }); + const result = await this.plugin.call('generate', input); + if (!result) throw new Error('generate: plugin returned no output'); + const output = result.json() as GenerateOutput; + + this.log(`generate: created DID ${output.did}`); + return output; + } + + /** + * Load database from serialized buffer + * + * @param database - Raw database bytes (from IPFS or storage) + * @returns Success status and loaded DID + */ + async load(database: Uint8Array | number[]): Promise { + this.log('load: loading database from buffer'); + + const dbArray = database instanceof Uint8Array ? Array.from(database) : database; + const input = JSON.stringify({ database: dbArray }); + const result = await this.plugin.call('load', input); + if (!result) throw new Error('load: plugin returned no output'); + const output = result.json() as LoadOutput; + + if (output.success) { + this.log(`load: loaded database for DID ${output.did}`); + } else { + this.log(`load: failed - ${output.error}`, 'error'); + } + + return output; + } + + /** + * Execute action with filter syntax + * + * @param filter - GitHub-style filter (e.g., "resource:accounts action:list") + * @param token - Optional UCAN token for authorization + * @returns Action result + */ + async exec(filter: string, token?: string): Promise { + this.log(`exec: executing filter "${filter}"`); + + const input = JSON.stringify({ filter, token }); + const result = await this.plugin.call('exec', input); + if (!result) throw new Error('exec: plugin returned no output'); + const output = result.json() as ExecOutput; + + if (output.success) { + this.log('exec: completed successfully'); + } else { + this.log(`exec: failed - ${output.error}`, 'error'); + } + + return output; + } + + /** + * Execute action with typed parameters + * + * @param resource - Resource type (accounts, credentials, sessions, grants) + * @param action - Action to perform + * @param options - Additional options + */ + async execute( + resource: Resource, + action: string, + options: { subject?: string; token?: string } = {} + ): Promise { + let filter = `resource:${resource} action:${action}`; + if (options.subject) { + filter += ` subject:${options.subject}`; + } + return this.exec(filter, options.token); + } + + /** + * Query DID document and associated resources + * + * @param did - DID to resolve (empty for current DID) + * @returns Resolved DID document with resources + */ + async query(did: string = ''): Promise { + this.log(`query: resolving DID ${did || '(current)'}`); + + const input = JSON.stringify({ did }); + const result = await this.plugin.call('query', input); + if (!result) throw new Error('query: plugin returned no output'); + const output = result.json() as QueryOutput; + + this.log(`query: resolved DID ${output.did}`); + return output; + } + + /** + * Reset plugin state + */ + async reset(): Promise { + this.log('reset: clearing plugin state'); + await this.plugin.reset(); + } + + /** + * Close and cleanup plugin resources + */ + async close(): Promise { + this.log('close: releasing plugin resources'); + await this.plugin.close(); + } + + private log(message: string, level: 'log' | 'error' | 'warn' | 'info' | 'debug' = 'debug'): void { + if (this.debug && this.logger) { + this.logger[level](`[Enclave] ${message}`); + } + } +} + +/** + * Create an Enclave instance + * + * @param wasm - URL string, file path, or Uint8Array of WASM bytes + * @param options - Configuration options + * + * @example + * ```typescript + * // From URL + * const enclave = await createEnclave('/enclave.wasm'); + * + * // From bytes + * const wasmBytes = await fetch('/enclave.wasm').then(r => r.arrayBuffer()); + * const enclave = await createEnclave(new Uint8Array(wasmBytes)); + * ``` + */ +export async function createEnclave( + wasm: string | Uint8Array, + options: EnclaveOptions = {} +): Promise { + return Enclave.create(wasm, options); +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..9760a0e --- /dev/null +++ b/src/index.ts @@ -0,0 +1,31 @@ +/** + * Motr Enclave - ESM wrapper for the Extism WebAssembly plugin + * + * @packageDocumentation + */ + +export { Enclave, createEnclave } from './enclave'; +export type { + // Input/Output types + GenerateInput, + GenerateOutput, + LoadInput, + LoadOutput, + ExecInput, + ExecOutput, + QueryInput, + QueryOutput, + // Shared types + VerificationMethod, + Account, + Credential, + // Options + EnclaveOptions, + // Filter types + Resource, + AccountAction, + CredentialAction, + SessionAction, + GrantAction, + FilterBuilder, +} from './types'; diff --git a/src/tsconfig.json b/src/tsconfig.json new file mode 100644 index 0000000..02fe294 --- /dev/null +++ b/src/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true, + "declarationMap": true, + "outDir": "../dist", + "rootDir": ".", + "types": ["bun-types"] + }, + "include": ["*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..cd4b300 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,129 @@ +/** + * TypeScript types for Motr Enclave plugin + * These types match the Go structs in main.go + */ + +// ============================================================================ +// Generate +// ============================================================================ + +export interface GenerateInput { + /** Base64-encoded PublicKeyCredential from WebAuthn registration */ + credential: string; +} + +export interface GenerateOutput { + /** The generated DID (e.g., "did:sonr:abc123") */ + did: string; + /** Serialized database buffer for storage */ + database: number[]; +} + +// ============================================================================ +// Load +// ============================================================================ + +export interface LoadInput { + /** Raw database bytes (typically from IPFS CID resolution) */ + database: number[]; +} + +export interface LoadOutput { + success: boolean; + did?: string; + error?: string; +} + +// ============================================================================ +// Exec +// ============================================================================ + +export interface ExecInput { + /** GitHub-style filter: "resource:accounts action:sign subject:did:sonr:abc" */ + filter: string; + /** UCAN token for authorization (optional) */ + token?: string; +} + +export interface ExecOutput { + success: boolean; + result?: unknown; + error?: string; +} + +// ============================================================================ +// Query +// ============================================================================ + +export interface QueryInput { + /** DID to resolve (empty string uses current DID) */ + did: string; +} + +export interface QueryOutput { + did: string; + controller: string; + verification_methods: VerificationMethod[]; + accounts: Account[]; + credentials: Credential[]; +} + +// ============================================================================ +// Shared Types +// ============================================================================ + +export interface VerificationMethod { + id: string; + type: string; + controller: string; + public_key: string; + purpose: string; +} + +export interface Account { + address: string; + chain_id: string; + coin_type: number; + account_index: number; + address_index: number; + label: string; + is_default: boolean; +} + +export interface Credential { + credential_id: string; + device_name: string; + device_type: string; + authenticator: string; + transports: string[]; + created_at: string; + last_used: string; +} + +// ============================================================================ +// Enclave Options +// ============================================================================ + +export interface EnclaveOptions { + /** Custom logger (defaults to console) */ + logger?: Pick; + /** Enable debug logging */ + debug?: boolean; +} + +// ============================================================================ +// Filter Builder Types +// ============================================================================ + +export type Resource = 'accounts' | 'credentials' | 'sessions' | 'grants'; +export type AccountAction = 'list' | 'sign'; +export type CredentialAction = 'list'; +export type SessionAction = 'list' | 'create' | 'revoke'; +export type GrantAction = 'list' | 'create' | 'revoke'; + +export interface FilterBuilder { + resource(r: Resource): this; + action(a: string): this; + subject(s: string): this; + build(): string; +}