wao 0.41.3 → 0.41.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc-cjs +5 -0
- package/.babelrc-esm +5 -0
- package/.gitmodules +4 -0
- package/.prettierrc +6 -0
- package/README.md +90 -0
- package/app/.eslintrc.json +3 -0
- package/app/.mocharc.cjs +6 -0
- package/app/arweave.mjs +87 -0
- package/app/components/Footer.js +76 -0
- package/app/components/Global.js +1128 -0
- package/app/components/Header.js +306 -0
- package/app/components/Left.js +28 -0
- package/app/components/Logo.js +34 -0
- package/app/components/Middle.js +37 -0
- package/app/components/Sidebar.js +93 -0
- package/app/components/Tags.js +42 -0
- package/app/components/editor/Editor.js +322 -0
- package/app/components/editor/FilePath.js +42 -0
- package/app/components/editor/MonacoEditor.js +44 -0
- package/app/components/left/LeftMessages.js +85 -0
- package/app/components/left/LeftModules.js +86 -0
- package/app/components/left/LeftNetworks.js +438 -0
- package/app/components/left/LeftProcesses.js +98 -0
- package/app/components/left/LeftProjects.js +397 -0
- package/app/components/left/LeftTests.js +189 -0
- package/app/components/middle/MiddleBlocks.js +79 -0
- package/app/components/middle/MiddleEntity.js +16 -0
- package/app/components/middle/MiddleEntityAccount.js +264 -0
- package/app/components/middle/MiddleEntityAssignment.js +104 -0
- package/app/components/middle/MiddleEntityBlock.js +148 -0
- package/app/components/middle/MiddleEntityMessage.js +430 -0
- package/app/components/middle/MiddleEntityModule.js +183 -0
- package/app/components/middle/MiddleEntityProcess.js +323 -0
- package/app/components/middle/MiddleEntityTx.js +211 -0
- package/app/components/middle/MiddleMessages.js +87 -0
- package/app/components/middle/MiddleModules.js +89 -0
- package/app/components/middle/MiddleNetworks.js +516 -0
- package/app/components/middle/MiddleProcesses.js +87 -0
- package/app/components/middle/MiddleTests.js +134 -0
- package/app/components/modals/CreateFileModal.js +115 -0
- package/app/components/modals/CreateFolderModal.js +83 -0
- package/app/components/modals/CreateProjectModal.js +63 -0
- package/app/components/modals/FSModal.js +141 -0
- package/app/components/modals/ImportModal.js +105 -0
- package/app/components/modals/LaunchNetworkModal.js +95 -0
- package/app/components/modals/Modal.js +38 -0
- package/app/components/modals/ProxyModal.js +122 -0
- package/app/components/modals/RenameFileModal.js +95 -0
- package/app/components/styles/EditorScrollbarStyle.js +29 -0
- package/app/components/styles/EntityScrollbarStyle.js +29 -0
- package/app/components/styles/GlobalStyle.js +102 -0
- package/app/components/styles/XtermStyle.js +37 -0
- package/app/components/terminal/Terminal.js +132 -0
- package/app/components/terminal/Xterm.js +160 -0
- package/app/components/ui/avatar.jsx +49 -0
- package/app/components/ui/checkbox.jsx +17 -0
- package/app/components/ui/close-button.jsx +20 -0
- package/app/components/ui/color-mode.jsx +61 -0
- package/app/components/ui/dialog.jsx +54 -0
- package/app/components/ui/drawer.jsx +44 -0
- package/app/components/ui/field.jsx +22 -0
- package/app/components/ui/input-group.jsx +39 -0
- package/app/components/ui/popover.jsx +49 -0
- package/app/components/ui/provider.jsx +12 -0
- package/app/components/ui/radio.jsx +17 -0
- package/app/components/ui/slider.jsx +107 -0
- package/app/components/ui/toaster.jsx +69 -0
- package/app/components/ui/tooltip.jsx +35 -0
- package/app/index.js +10 -0
- package/app/jsconfig.json +7 -0
- package/app/lib/GithubCSS.js +1218 -0
- package/app/lib/addon-fit.js +72 -0
- package/app/lib/data.js +31 -0
- package/app/lib/github-markdown.css +1169 -0
- package/app/lib/global.js +1 -0
- package/app/lib/guide.js +82 -0
- package/app/lib/hub.js +109 -0
- package/app/lib/scripts.js +47 -0
- package/app/lib/store.js +34 -0
- package/app/lib/use.js +64 -0
- package/app/lib/utils.js +387 -0
- package/app/lib/webrtc.js +217 -0
- package/app/next.config.js +25 -0
- package/app/package.json +62 -0
- package/app/pages/404.js +9 -0
- package/app/pages/_app.js +10 -0
- package/app/pages/_document.js +14 -0
- package/app/pages/index.js +121 -0
- package/app/playwright.config.mjs +41 -0
- package/app/proxy.mjs +21 -0
- package/app/public/assets/cover.png +0 -0
- package/app/public/blueprints/apm.lua +91 -0
- package/app/public/blueprints/arena.lua +345 -0
- package/app/public/blueprints/arns.lua +318 -0
- package/app/public/blueprints/chat.lua +210 -0
- package/app/public/blueprints/chatroom.lua +56 -0
- package/app/public/blueprints/patch-legacy-reply.lua +13 -0
- package/app/public/blueprints/staking.lua +93 -0
- package/app/public/blueprints/token.lua +298 -0
- package/app/public/blueprints/voting.lua +45 -0
- package/app/public/favicon.ico +0 -0
- package/app/public/logo.png +0 -0
- package/cli-esm.js +55 -0
- package/cli.js +54 -0
- package/devnet/app/api.js +129 -0
- package/devnet/app/components/layout.js +89 -0
- package/devnet/app/components/pagination.js +144 -0
- package/devnet/app/components/search.js +159 -0
- package/devnet/app/components/table.js +124 -0
- package/devnet/app/components/tags.js +89 -0
- package/devnet/app/index.html +14 -0
- package/devnet/app/main.js +215 -0
- package/devnet/app/router.js +59 -0
- package/devnet/app/state.js +19 -0
- package/devnet/app/style.css +1606 -0
- package/devnet/app/utils.js +77 -0
- package/devnet/app/views/blocks.js +75 -0
- package/devnet/app/views/dashboard.js +127 -0
- package/devnet/app/views/entity.js +1473 -0
- package/devnet/app/views/messages.js +90 -0
- package/devnet/app/views/modules.js +165 -0
- package/devnet/app/views/processes.js +90 -0
- package/devnet/app/views/schedulers.js +90 -0
- package/devnet/app/views/transactions.js +88 -0
- package/devnet/migrations/0001_initial.sql +51 -0
- package/devnet/package.json +26 -0
- package/devnet/playwright.config.js +7 -0
- package/devnet/src/cu-worker.js +166 -0
- package/devnet/src/index.js +309 -0
- package/devnet/vite.config.js +17 -0
- package/devnet/vitest.config.js +10 -0
- package/devnet/wrangler-cu.toml +32 -0
- package/devnet/wrangler.toml +38 -0
- package/dhfs-tutorial-app/package.json +15 -0
- package/dist/esm/workspace/dashboard/public/favicon.png +0 -0
- package/dist/esm/workspace/src/counter.lua +14 -0
- package/dist/package.json +82 -0
- package/hb.sh +18 -0
- package/hbsig/.babelrc-cjs +5 -0
- package/hbsig/.babelrc-esm +5 -0
- package/hbsig/README.md +1 -0
- package/hbsig/dist/cjs/bin_to_str.js +44 -0
- package/hbsig/dist/cjs/collect-body-keys.js +470 -0
- package/hbsig/dist/cjs/commit.js +330 -0
- package/hbsig/dist/cjs/encode-array-item.js +110 -0
- package/hbsig/dist/cjs/encode-utils.js +242 -0
- package/hbsig/dist/cjs/encode.js +1365 -0
- package/hbsig/dist/cjs/erl_json.js +326 -0
- package/hbsig/dist/cjs/erl_str.js +1042 -0
- package/hbsig/dist/cjs/flat.js +279 -0
- package/hbsig/dist/cjs/http-message-signatures/httpbis.js +489 -0
- package/hbsig/dist/cjs/http-message-signatures/index.js +25 -0
- package/hbsig/dist/cjs/http-message-signatures/structured-header.js +129 -0
- package/hbsig/dist/cjs/httpsig.js +861 -0
- package/hbsig/dist/cjs/id.js +470 -0
- package/hbsig/dist/cjs/index.js +174 -0
- package/hbsig/dist/cjs/nocrypto.js +51 -0
- package/hbsig/dist/cjs/parser.js +201 -0
- package/hbsig/dist/cjs/send-utils.js +1231 -0
- package/hbsig/dist/cjs/send.js +211 -0
- package/hbsig/dist/cjs/signer-utils.js +494 -0
- package/hbsig/dist/cjs/signer.js +436 -0
- package/hbsig/dist/cjs/structured.js +515 -0
- package/hbsig/dist/cjs/test.js +12 -0
- package/hbsig/dist/cjs/utils.js +44 -0
- package/hbsig/dist/esm/bin_to_str.js +46 -0
- package/hbsig/dist/esm/collect-body-keys.js +436 -0
- package/hbsig/dist/esm/commit.js +219 -0
- package/hbsig/dist/esm/encode-array-item.js +112 -0
- package/hbsig/dist/esm/encode-utils.js +191 -0
- package/hbsig/dist/esm/encode.js +1256 -0
- package/hbsig/dist/esm/erl_json.js +292 -0
- package/hbsig/dist/esm/erl_str.js +1144 -0
- package/hbsig/dist/esm/flat.js +250 -0
- package/hbsig/dist/esm/http-message-signatures/httpbis.js +438 -0
- package/hbsig/dist/esm/http-message-signatures/index.js +4 -0
- package/hbsig/dist/esm/http-message-signatures/structured-header.js +105 -0
- package/hbsig/dist/esm/httpsig.js +866 -0
- package/hbsig/dist/esm/id.js +459 -0
- package/hbsig/dist/esm/index.js +13 -0
- package/hbsig/dist/esm/nocrypto.js +4 -0
- package/hbsig/dist/esm/package.json +3 -0
- package/hbsig/dist/esm/parser.js +171 -0
- package/hbsig/dist/esm/send-utils.js +1132 -0
- package/hbsig/dist/esm/send.js +142 -0
- package/hbsig/dist/esm/signer-utils.js +375 -0
- package/hbsig/dist/esm/signer.js +312 -0
- package/hbsig/dist/esm/structured.js +496 -0
- package/hbsig/dist/esm/test.js +2 -0
- package/hbsig/dist/esm/utils.js +29 -0
- package/hbsig/dist/package.json +39 -0
- package/hbsig/make.js +36 -0
- package/hbsig/package.json +39 -0
- package/hbsig/src/bin_to_str.js +46 -0
- package/hbsig/src/collect-body-keys.js +436 -0
- package/hbsig/src/commit.js +219 -0
- package/hbsig/src/encode-array-item.js +112 -0
- package/hbsig/src/encode-utils.js +191 -0
- package/hbsig/src/encode.js +1256 -0
- package/hbsig/src/erl_json.js +292 -0
- package/hbsig/src/erl_str.js +1144 -0
- package/hbsig/src/flat.js +250 -0
- package/hbsig/src/http-message-signatures/httpbis.js +438 -0
- package/hbsig/src/http-message-signatures/index.js +4 -0
- package/hbsig/src/http-message-signatures/structured-header.js +105 -0
- package/hbsig/src/httpsig.js +866 -0
- package/hbsig/src/id.js +459 -0
- package/hbsig/src/index.js +13 -0
- package/hbsig/src/nocrypto.js +4 -0
- package/hbsig/src/parser.js +171 -0
- package/hbsig/src/send-utils.js +1132 -0
- package/hbsig/src/send.js +142 -0
- package/hbsig/src/signer-utils.js +375 -0
- package/hbsig/src/signer.js +312 -0
- package/hbsig/src/structured.js +496 -0
- package/hbsig/src/test.js +2 -0
- package/hbsig/src/utils.js +29 -0
- package/lp/index.html +25 -0
- package/lp/package.json +19 -0
- package/lp/public/cover.png +0 -0
- package/lp/public/favicon.ico +0 -0
- package/lp/public/favicon.png +0 -0
- package/lp/public/images/book.jpg +0 -0
- package/lp/public/images/dashboard.png +0 -0
- package/lp/public/images/devnet.png +0 -0
- package/lp/public/images/hero-bg.png +0 -0
- package/lp/public/images/hyperadd.png +0 -0
- package/lp/public/images/message-flow.png +0 -0
- package/lp/public/images/mobile.png +0 -0
- package/lp/public/images/og-cover.png +0 -0
- package/lp/public/images/scan.png +0 -0
- package/lp/public/images/wao-hub.png +0 -0
- package/lp/public/images/wao-web.png +0 -0
- package/lp/public/logo.png +0 -0
- package/lp/src/App.jsx +29 -0
- package/lp/src/components/CodeBlock.jsx +37 -0
- package/lp/src/components/CodeBlock.module.css +89 -0
- package/lp/src/components/Footer.jsx +22 -0
- package/lp/src/components/Footer.module.css +60 -0
- package/lp/src/components/Nav.jsx +80 -0
- package/lp/src/components/Nav.module.css +177 -0
- package/lp/src/components/SectionWrapper.jsx +15 -0
- package/lp/src/hooks/useReveal.js +25 -0
- package/lp/src/hooks/useScrolled.js +14 -0
- package/lp/src/main.jsx +10 -0
- package/lp/src/sections/Book.jsx +60 -0
- package/lp/src/sections/Book.module.css +204 -0
- package/lp/src/sections/Browser.jsx +46 -0
- package/lp/src/sections/Browser.module.css +67 -0
- package/lp/src/sections/Devnet.jsx +55 -0
- package/lp/src/sections/Devnet.module.css +136 -0
- package/lp/src/sections/GetStarted.jsx +51 -0
- package/lp/src/sections/GetStarted.module.css +128 -0
- package/lp/src/sections/Hero.jsx +67 -0
- package/lp/src/sections/Hero.module.css +202 -0
- package/lp/src/sections/HyperADD.jsx +46 -0
- package/lp/src/sections/HyperADD.module.css +113 -0
- package/lp/src/sections/SDK.jsx +90 -0
- package/lp/src/sections/SDK.module.css +122 -0
- package/lp/src/sections/Testing.jsx +47 -0
- package/lp/src/sections/Testing.module.css +124 -0
- package/lp/src/sections/Vision.jsx +93 -0
- package/lp/src/sections/Vision.module.css +147 -0
- package/lp/src/styles/globals.css +285 -0
- package/lp/src/utils/scrollTo.js +4 -0
- package/lp/vite.config.js +7 -0
- package/make.js +39 -0
- package/package.json +17 -12
- package/patches/@permaweb+ao-loader+0.0.44.patch +64 -0
- package/plan.md +435 -0
- package/rebar.lock +1 -0
- package/src/accounts-web.js +128 -0
- package/src/accounts.js +124 -0
- package/src/adaptor-base.js +622 -0
- package/src/adaptor-cf.js +11 -0
- package/src/adaptor-web.js +11 -0
- package/src/adaptor.js +10 -0
- package/src/ao-loader.js +30660 -0
- package/src/ao.js +1173 -0
- package/src/aoconnect-base.js +1098 -0
- package/src/aoconnect-cf.js +9 -0
- package/src/aoconnect-web.js +8 -0
- package/src/aoconnect.js +8 -0
- package/src/aos_wamr.js +1 -0
- package/src/ar-remote.js +87 -0
- package/src/ar.js +276 -0
- package/src/armem-base.js +529 -0
- package/src/armem-cf.js +67 -0
- package/src/armem-web.js +19 -0
- package/src/armem.js +26 -0
- package/src/bao.js +141 -0
- package/src/bar.js +366 -0
- package/src/build.js +7 -0
- package/src/bundler.js +119 -0
- package/src/car.js +10 -0
- package/src/cf-env.js +29 -0
- package/src/cf.js +11 -0
- package/src/cli.js +561 -0
- package/src/compress.js +112 -0
- package/src/create.js +415 -0
- package/src/devs.js +86 -0
- package/src/dirname.js +1 -0
- package/src/dodb.js +26 -0
- package/src/erl_json.js +289 -0
- package/src/erl_str.js +1139 -0
- package/src/gql.js +229 -0
- package/src/hb.js +967 -0
- package/src/helpers.js +203 -0
- package/src/http.js +619 -0
- package/src/hub/bundler.js +123 -0
- package/src/hub/cu.js +74 -0
- package/src/hub/fs.js +157 -0
- package/src/hub/index.js +85 -0
- package/src/hub/utils.js +64 -0
- package/src/hub/ws-proxy.js +67 -0
- package/src/hyper-aos.js +1 -0
- package/src/hyperbeam-server.js +21 -0
- package/src/hyperbeam.js +585 -0
- package/src/index.js +5 -0
- package/src/keygen.js +47 -0
- package/src/lfdb.js +67 -0
- package/src/lua/aos.wasm +0 -0
- package/src/lua/aos2_0_1.js +1 -0
- package/src/lua/aos2_0_1.wasm +0 -0
- package/src/lua/aos2_0_3.js +1 -0
- package/src/lua/aos2_0_3.wasm +0 -0
- package/src/lua/aos2_0_4_32.js +1 -0
- package/src/lua/aos2_0_4_32.wasm +0 -0
- package/src/lua/aos2_0_6.wasm +0 -0
- package/src/lua/apm.lua +61 -0
- package/src/lua/llama.wasm +0 -0
- package/src/lua/process.wasm +0 -0
- package/src/lua/sqlite.js +1 -0
- package/src/lua/sqlite.wasm +0 -0
- package/src/lua/weavedb_mock.lua +44 -0
- package/src/lua/weavedrive.lua +53 -0
- package/src/run.js +25 -0
- package/src/server.js +173 -0
- package/src/storage-multi.js +183 -0
- package/src/tao.js +12 -0
- package/src/tar.js +10 -0
- package/src/test.js +42 -0
- package/src/tgql-d1.js +407 -0
- package/src/tgql.js +310 -0
- package/src/toerl.js +162 -0
- package/src/utils.js +777 -0
- package/src/wao.js +29 -0
- package/src/waosm/README.md +81 -0
- package/src/waosm/waosm.d.ts +40 -0
- package/src/waosm/waosm.js +240 -0
- package/src/waosm/waosm_bg.wasm +0 -0
- package/src/waosm/waosm_bg.wasm.d.ts +8 -0
- package/src/waosm-node/README.md +81 -0
- package/src/waosm-node/waosm.d.ts +8 -0
- package/src/waosm-node/waosm.js +4 -0
- package/src/waosm-node/waosm_bg.js +147 -0
- package/src/waosm-node/waosm_bg.wasm +0 -0
- package/src/waosm-node/waosm_bg.wasm.d.ts +8 -0
- package/src/waosm-node/waosm_bg.wasm.js +14 -0
- package/src/waosm-node.js +9 -0
- package/src/war.js +10 -0
- package/src/weavedrive.js +376 -0
- package/src/web.js +11 -0
- package/src/workspace/.mcp.json +8 -0
- package/src/workspace/CLAUDE.md +258 -0
- package/src/workspace/README.md +85 -0
- package/src/workspace/dashboard/index.html +163 -0
- package/src/workspace/dashboard/package.json +18 -0
- package/src/workspace/dashboard/public/favicon.ico +0 -0
- package/src/workspace/dashboard/public/favicon.png +0 -0
- package/src/workspace/dashboard/server.js +224 -0
- package/src/workspace/dashboard/src/App.jsx +2350 -0
- package/{cjs/workspace/frontend → src/workspace/dashboard}/vite.config.js +6 -0
- package/src/workspace/package.json +18 -0
- package/src/workspace/src/counter.lua +14 -0
- package/tsconfig.json +18 -0
- package/types/index.d.ts +329 -0
- package/waollama/.eslintrc.json +3 -0
- package/waollama/README.md +19 -0
- package/waollama/arweave.mjs +87 -0
- package/waollama/components/ui/avatar.jsx +49 -0
- package/waollama/components/ui/checkbox.jsx +17 -0
- package/waollama/components/ui/close-button.jsx +20 -0
- package/waollama/components/ui/color-mode.jsx +61 -0
- package/waollama/components/ui/dialog.jsx +54 -0
- package/waollama/components/ui/drawer.jsx +44 -0
- package/waollama/components/ui/field.jsx +22 -0
- package/waollama/components/ui/input-group.jsx +39 -0
- package/waollama/components/ui/popover.jsx +49 -0
- package/waollama/components/ui/provider.jsx +12 -0
- package/waollama/components/ui/radio.jsx +17 -0
- package/waollama/components/ui/slider.jsx +107 -0
- package/waollama/components/ui/tooltip.jsx +35 -0
- package/waollama/index.js +10 -0
- package/waollama/jsconfig.json +7 -0
- package/waollama/lib/ao-loader.js +30654 -0
- package/waollama/lib/client.js +1 -0
- package/waollama/lib/wasm.js +1 -0
- package/waollama/next.config.js +25 -0
- package/waollama/package.json +43 -0
- package/waollama/pages/404.js +9 -0
- package/waollama/pages/_app.js +9 -0
- package/waollama/pages/_document.js +14 -0
- package/waollama/pages/index.js +212 -0
- package/waollama/playwright.config.js +31 -0
- package/waollama/proxy.mjs +21 -0
- package/waollama/public/favicon.ico +0 -0
- package/waollama/public/human.png +0 -0
- package/waollama/public/llama.png +0 -0
- package/waosm/Cargo.toml +11 -0
- package/waosm/README.md +81 -0
- package/waosm/compress.js +112 -0
- package/waosm/make.js +33 -0
- package/waosm/package.json +10 -0
- package/waosm/src/lib.rs +180 -0
- package/waosm/test.js +16 -0
- package/cjs/workspace/.claude/agents/builder.md +0 -99
- package/cjs/workspace/.claude/agents/device-builder.md +0 -86
- package/cjs/workspace/.claude/agents/tester.md +0 -90
- package/cjs/workspace/.claude/mcp/dashboard/server.js +0 -128
- package/cjs/workspace/.claude/rules/deploy.md +0 -45
- package/cjs/workspace/.claude/rules/frontend.md +0 -69
- package/cjs/workspace/.claude/rules/hyperbeam.md +0 -104
- package/cjs/workspace/.claude/rules/lua.md +0 -108
- package/cjs/workspace/.claude/rules/testing.md +0 -257
- package/cjs/workspace/.claude/settings.json +0 -109
- package/cjs/workspace/.claude/skills/build/SKILL.md +0 -214
- package/cjs/workspace/.claude/skills/build-aos/SKILL.md +0 -129
- package/cjs/workspace/.claude/skills/build-device/SKILL.md +0 -192
- package/cjs/workspace/.claude/skills/build-frontend/SKILL.md +0 -134
- package/cjs/workspace/.claude/skills/build-module/SKILL.md +0 -281
- package/cjs/workspace/.claude/skills/create-aos/SKILL.md +0 -63
- package/cjs/workspace/.claude/skills/create-device/SKILL.md +0 -87
- package/cjs/workspace/.claude/skills/create-module/SKILL.md +0 -162
- package/cjs/workspace/.claude/skills/debug/SKILL.md +0 -57
- package/cjs/workspace/.claude/skills/deploy/SKILL.md +0 -85
- package/cjs/workspace/.claude/skills/dev/SKILL.md +0 -32
- package/cjs/workspace/.claude/skills/plan/SKILL.md +0 -176
- package/cjs/workspace/.claude/skills/readme/SKILL.md +0 -186
- package/cjs/workspace/.claude/skills/report/SKILL.md +0 -49
- package/cjs/workspace/.claude/skills/team/SKILL.md +0 -101
- package/cjs/workspace/.claude/skills/test/SKILL.md +0 -56
- package/cjs/workspace/.claude/skills/test-device/SKILL.md +0 -114
- package/cjs/workspace/.claude/skills/test-e2e/SKILL.md +0 -103
- package/cjs/workspace/.claude/skills/test-hb/SKILL.md +0 -76
- package/cjs/workspace/.claude/skills/validate/SKILL.md +0 -96
- package/cjs/workspace/.claude/skills/validate/scripts/check-lua.sh +0 -41
- package/cjs/workspace/docs/aos-lua.md +0 -428
- package/cjs/workspace/docs/debug.md +0 -230
- package/cjs/workspace/docs/hyperbeam-dev.md +0 -606
- package/cjs/workspace/docs/hyperbeam-devices.md +0 -618
- package/cjs/workspace/docs/wao-sdk.md +0 -807
- package/cjs/workspace/frontend/e2e/.gitkeep +0 -0
- package/cjs/workspace/frontend/index.html +0 -12
- package/cjs/workspace/frontend/package.json +0 -24
- package/cjs/workspace/frontend/playwright.config.js +0 -10
- package/cjs/workspace/frontend/src/App.jsx +0 -24
- package/cjs/workspace/frontend/test/.gitkeep +0 -0
- package/cjs/workspace/frontend/vitest.config.js +0 -10
- package/cjs/workspace/scripts/deploy.js +0 -140
- package/cjs/workspace/scripts/keygen.js +0 -52
- package/cjs/workspace/test/aos.test.js +0 -98
- package/cjs/workspace/test/hyperbeam.test.js +0 -80
- package/esm/compiler/native +0 -0
- package/esm/workspace/.claude/agents/builder.md +0 -99
- package/esm/workspace/.claude/agents/device-builder.md +0 -86
- package/esm/workspace/.claude/agents/tester.md +0 -90
- package/esm/workspace/.claude/mcp/dashboard/server.js +0 -128
- package/esm/workspace/.claude/rules/deploy.md +0 -45
- package/esm/workspace/.claude/rules/frontend.md +0 -69
- package/esm/workspace/.claude/rules/hyperbeam.md +0 -104
- package/esm/workspace/.claude/rules/lua.md +0 -108
- package/esm/workspace/.claude/rules/testing.md +0 -257
- package/esm/workspace/.claude/settings.json +0 -109
- package/esm/workspace/.claude/skills/build/SKILL.md +0 -214
- package/esm/workspace/.claude/skills/build-aos/SKILL.md +0 -129
- package/esm/workspace/.claude/skills/build-device/SKILL.md +0 -192
- package/esm/workspace/.claude/skills/build-frontend/SKILL.md +0 -134
- package/esm/workspace/.claude/skills/build-module/SKILL.md +0 -281
- package/esm/workspace/.claude/skills/create-aos/SKILL.md +0 -63
- package/esm/workspace/.claude/skills/create-device/SKILL.md +0 -87
- package/esm/workspace/.claude/skills/create-module/SKILL.md +0 -162
- package/esm/workspace/.claude/skills/debug/SKILL.md +0 -57
- package/esm/workspace/.claude/skills/deploy/SKILL.md +0 -85
- package/esm/workspace/.claude/skills/dev/SKILL.md +0 -32
- package/esm/workspace/.claude/skills/plan/SKILL.md +0 -176
- package/esm/workspace/.claude/skills/readme/SKILL.md +0 -186
- package/esm/workspace/.claude/skills/report/SKILL.md +0 -49
- package/esm/workspace/.claude/skills/team/SKILL.md +0 -101
- package/esm/workspace/.claude/skills/test/SKILL.md +0 -56
- package/esm/workspace/.claude/skills/test-device/SKILL.md +0 -114
- package/esm/workspace/.claude/skills/test-e2e/SKILL.md +0 -103
- package/esm/workspace/.claude/skills/test-hb/SKILL.md +0 -76
- package/esm/workspace/.claude/skills/validate/SKILL.md +0 -96
- package/esm/workspace/.claude/skills/validate/scripts/check-lua.sh +0 -41
- package/esm/workspace/docs/aos-lua.md +0 -428
- package/esm/workspace/docs/debug.md +0 -230
- package/esm/workspace/docs/hyperbeam-dev.md +0 -606
- package/esm/workspace/docs/hyperbeam-devices.md +0 -618
- package/esm/workspace/docs/wao-sdk.md +0 -807
- package/esm/workspace/frontend/e2e/.gitkeep +0 -0
- package/esm/workspace/frontend/index.html +0 -12
- package/esm/workspace/frontend/package.json +0 -24
- package/esm/workspace/frontend/playwright.config.js +0 -10
- package/esm/workspace/frontend/src/App.jsx +0 -24
- package/esm/workspace/frontend/src/main.jsx +0 -9
- package/esm/workspace/frontend/test/.gitkeep +0 -0
- package/esm/workspace/frontend/vite.config.js +0 -6
- package/esm/workspace/frontend/vitest.config.js +0 -10
- package/esm/workspace/scripts/deploy.js +0 -140
- package/esm/workspace/scripts/keygen.js +0 -52
- package/esm/workspace/test/aos.test.js +0 -98
- package/esm/workspace/test/hyperbeam.test.js +0 -80
- /package/{cjs/workspace/dashboard/public → devnet/app}/favicon.ico +0 -0
- /package/{cjs/workspace → dhfs-tutorial-app}/src/counter.lua +0 -0
- /package/{cjs → dist/cjs}/accounts-web.js +0 -0
- /package/{cjs → dist/cjs}/accounts.js +0 -0
- /package/{cjs → dist/cjs}/adaptor-base.js +0 -0
- /package/{cjs → dist/cjs}/adaptor-cf.js +0 -0
- /package/{cjs → dist/cjs}/adaptor-web.js +0 -0
- /package/{cjs → dist/cjs}/adaptor.js +0 -0
- /package/{cjs → dist/cjs}/ao-loader.js +0 -0
- /package/{cjs → dist/cjs}/ao.js +0 -0
- /package/{cjs → dist/cjs}/aoconnect-base.js +0 -0
- /package/{cjs → dist/cjs}/aoconnect-cf.js +0 -0
- /package/{cjs → dist/cjs}/aoconnect-web.js +0 -0
- /package/{cjs → dist/cjs}/aoconnect.js +0 -0
- /package/{cjs → dist/cjs}/aos_wamr.js +0 -0
- /package/{cjs → dist/cjs}/ar-remote.js +0 -0
- /package/{cjs → dist/cjs}/ar.js +0 -0
- /package/{cjs → dist/cjs}/armem-base.js +0 -0
- /package/{cjs → dist/cjs}/armem-cf.js +0 -0
- /package/{cjs → dist/cjs}/armem-web.js +0 -0
- /package/{cjs → dist/cjs}/armem.js +0 -0
- /package/{cjs → dist/cjs}/bao.js +0 -0
- /package/{cjs → dist/cjs}/bar.js +0 -0
- /package/{cjs → dist/cjs}/build.js +0 -0
- /package/{cjs → dist/cjs}/bundler.js +0 -0
- /package/{cjs → dist/cjs}/car.js +0 -0
- /package/{cjs → dist/cjs}/cf-env.js +0 -0
- /package/{cjs → dist/cjs}/cf.js +0 -0
- /package/{cjs → dist/cjs}/cli.js +0 -0
- /package/{cjs → dist/cjs}/compress.js +0 -0
- /package/{cjs → dist/cjs}/create.js +0 -0
- /package/{cjs → dist/cjs}/devs.js +0 -0
- /package/{cjs → dist/cjs}/dirname.js +0 -0
- /package/{cjs → dist/cjs}/dodb.js +0 -0
- /package/{cjs → dist/cjs}/erl_json.js +0 -0
- /package/{cjs → dist/cjs}/erl_str.js +0 -0
- /package/{cjs → dist/cjs}/gql.js +0 -0
- /package/{cjs → dist/cjs}/hb.js +0 -0
- /package/{cjs → dist/cjs}/helpers.js +0 -0
- /package/{cjs → dist/cjs}/http.js +0 -0
- /package/{cjs → dist/cjs}/hub/bundler.js +0 -0
- /package/{cjs → dist/cjs}/hub/cu.js +0 -0
- /package/{cjs → dist/cjs}/hub/fs.js +0 -0
- /package/{cjs → dist/cjs}/hub/index.js +0 -0
- /package/{cjs → dist/cjs}/hub/utils.js +0 -0
- /package/{cjs → dist/cjs}/hub/ws-proxy.js +0 -0
- /package/{cjs → dist/cjs}/hyper-aos.js +0 -0
- /package/{cjs → dist/cjs}/hyperbeam-server.js +0 -0
- /package/{cjs → dist/cjs}/hyperbeam.js +0 -0
- /package/{cjs → dist/cjs}/index.js +0 -0
- /package/{cjs → dist/cjs}/keygen.js +0 -0
- /package/{cjs → dist/cjs}/lfdb.js +0 -0
- /package/{cjs → dist/cjs}/lua/aos.wasm +0 -0
- /package/{cjs → dist/cjs}/lua/aos2_0_1.js +0 -0
- /package/{cjs → dist/cjs}/lua/aos2_0_1.wasm +0 -0
- /package/{cjs → dist/cjs}/lua/aos2_0_3.js +0 -0
- /package/{cjs → dist/cjs}/lua/aos2_0_3.wasm +0 -0
- /package/{cjs → dist/cjs}/lua/aos2_0_4_32.js +0 -0
- /package/{cjs → dist/cjs}/lua/aos2_0_4_32.wasm +0 -0
- /package/{cjs → dist/cjs}/lua/aos2_0_6.wasm +0 -0
- /package/{cjs → dist/cjs}/lua/apm.lua +0 -0
- /package/{cjs → dist/cjs}/lua/llama.wasm +0 -0
- /package/{cjs → dist/cjs}/lua/process.wasm +0 -0
- /package/{cjs → dist/cjs}/lua/sqlite.js +0 -0
- /package/{cjs → dist/cjs}/lua/sqlite.wasm +0 -0
- /package/{cjs → dist/cjs}/lua/weavedb_mock.lua +0 -0
- /package/{cjs → dist/cjs}/lua/weavedrive.lua +0 -0
- /package/{cjs → dist/cjs}/run.js +0 -0
- /package/{cjs → dist/cjs}/server.js +0 -0
- /package/{cjs → dist/cjs}/storage-multi.js +0 -0
- /package/{cjs → dist/cjs}/tao.js +0 -0
- /package/{cjs → dist/cjs}/tar.js +0 -0
- /package/{cjs → dist/cjs}/test.js +0 -0
- /package/{cjs → dist/cjs}/tgql-d1.js +0 -0
- /package/{cjs → dist/cjs}/tgql.js +0 -0
- /package/{cjs → dist/cjs}/toerl.js +0 -0
- /package/{cjs → dist/cjs}/utils.js +0 -0
- /package/{cjs → dist/cjs}/wao.js +0 -0
- /package/{cjs → dist/cjs}/waosm/waosm.js +0 -0
- /package/{cjs → dist/cjs}/waosm-node/waosm.js +0 -0
- /package/{cjs → dist/cjs}/waosm-node/waosm_bg.js +0 -0
- /package/{cjs → dist/cjs}/waosm-node/waosm_bg.wasm +0 -0
- /package/{cjs → dist/cjs}/waosm-node/waosm_bg.wasm.js +0 -0
- /package/{cjs → dist/cjs}/waosm-node.js +0 -0
- /package/{cjs → dist/cjs}/war.js +0 -0
- /package/{cjs → dist/cjs}/weavedrive.js +0 -0
- /package/{cjs → dist/cjs}/web.js +0 -0
- /package/{cjs → dist/cjs}/workspace/.mcp.json +0 -0
- /package/{cjs → dist/cjs}/workspace/CLAUDE.md +0 -0
- /package/{cjs → dist/cjs}/workspace/README.md +0 -0
- /package/{cjs → dist/cjs}/workspace/dashboard/index.html +0 -0
- /package/{cjs → dist/cjs}/workspace/dashboard/package.json +0 -0
- /package/{esm → dist/cjs}/workspace/dashboard/public/favicon.ico +0 -0
- /package/{cjs → dist/cjs}/workspace/dashboard/public/favicon.png +0 -0
- /package/{cjs → dist/cjs}/workspace/dashboard/server.js +0 -0
- /package/{cjs → dist/cjs}/workspace/dashboard/src/App.jsx +0 -0
- /package/{cjs → dist/cjs}/workspace/dashboard/src/main.jsx +0 -0
- /package/{cjs → dist/cjs}/workspace/dashboard/vite.config.js +0 -0
- /package/{cjs → dist/cjs}/workspace/package.json +0 -0
- /package/{esm → dist/cjs}/workspace/src/counter.lua +0 -0
- /package/{esm → dist/esm}/accounts-web.js +0 -0
- /package/{esm → dist/esm}/accounts.js +0 -0
- /package/{esm → dist/esm}/adaptor-base.js +0 -0
- /package/{esm → dist/esm}/adaptor-cf.js +0 -0
- /package/{esm → dist/esm}/adaptor-web.js +0 -0
- /package/{esm → dist/esm}/adaptor.js +0 -0
- /package/{esm → dist/esm}/ao-loader.js +0 -0
- /package/{esm → dist/esm}/ao.js +0 -0
- /package/{esm → dist/esm}/aoconnect-base.js +0 -0
- /package/{esm → dist/esm}/aoconnect-cf.js +0 -0
- /package/{esm → dist/esm}/aoconnect-web.js +0 -0
- /package/{esm → dist/esm}/aoconnect.js +0 -0
- /package/{esm → dist/esm}/aos_wamr.js +0 -0
- /package/{esm → dist/esm}/ar-remote.js +0 -0
- /package/{esm → dist/esm}/ar.js +0 -0
- /package/{esm → dist/esm}/armem-base.js +0 -0
- /package/{esm → dist/esm}/armem-cf.js +0 -0
- /package/{esm → dist/esm}/armem-web.js +0 -0
- /package/{esm → dist/esm}/armem.js +0 -0
- /package/{esm → dist/esm}/bao.js +0 -0
- /package/{esm → dist/esm}/bar.js +0 -0
- /package/{esm → dist/esm}/build.js +0 -0
- /package/{esm → dist/esm}/bundler.js +0 -0
- /package/{esm → dist/esm}/car.js +0 -0
- /package/{esm → dist/esm}/cf-env.js +0 -0
- /package/{esm → dist/esm}/cf.js +0 -0
- /package/{esm → dist/esm}/cli.js +0 -0
- /package/{esm → dist/esm}/compress.js +0 -0
- /package/{esm → dist/esm}/create.js +0 -0
- /package/{esm → dist/esm}/devs.js +0 -0
- /package/{esm → dist/esm}/dirname.js +0 -0
- /package/{esm → dist/esm}/dodb.js +0 -0
- /package/{esm → dist/esm}/erl_json.js +0 -0
- /package/{esm → dist/esm}/erl_str.js +0 -0
- /package/{esm → dist/esm}/gql.js +0 -0
- /package/{esm → dist/esm}/hb.js +0 -0
- /package/{esm → dist/esm}/helpers.js +0 -0
- /package/{esm → dist/esm}/http.js +0 -0
- /package/{esm → dist/esm}/hub/bundler.js +0 -0
- /package/{esm → dist/esm}/hub/cu.js +0 -0
- /package/{esm → dist/esm}/hub/fs.js +0 -0
- /package/{esm → dist/esm}/hub/index.js +0 -0
- /package/{esm → dist/esm}/hub/utils.js +0 -0
- /package/{esm → dist/esm}/hub/ws-proxy.js +0 -0
- /package/{esm → dist/esm}/hyper-aos.js +0 -0
- /package/{esm → dist/esm}/hyperbeam-server.js +0 -0
- /package/{esm → dist/esm}/hyperbeam.js +0 -0
- /package/{esm → dist/esm}/index.js +0 -0
- /package/{esm → dist/esm}/keygen.js +0 -0
- /package/{esm → dist/esm}/lfdb.js +0 -0
- /package/{esm → dist/esm}/lua/aos.wasm +0 -0
- /package/{esm → dist/esm}/lua/aos2_0_1.js +0 -0
- /package/{esm → dist/esm}/lua/aos2_0_1.wasm +0 -0
- /package/{esm → dist/esm}/lua/aos2_0_3.js +0 -0
- /package/{esm → dist/esm}/lua/aos2_0_3.wasm +0 -0
- /package/{esm → dist/esm}/lua/aos2_0_4_32.js +0 -0
- /package/{esm → dist/esm}/lua/aos2_0_4_32.wasm +0 -0
- /package/{esm → dist/esm}/lua/aos2_0_6.wasm +0 -0
- /package/{esm → dist/esm}/lua/apm.lua +0 -0
- /package/{esm → dist/esm}/lua/llama.wasm +0 -0
- /package/{esm → dist/esm}/lua/process.wasm +0 -0
- /package/{esm → dist/esm}/lua/sqlite.js +0 -0
- /package/{esm → dist/esm}/lua/sqlite.wasm +0 -0
- /package/{esm → dist/esm}/lua/weavedb_mock.lua +0 -0
- /package/{esm → dist/esm}/lua/weavedrive.lua +0 -0
- /package/{esm → dist/esm}/package.json +0 -0
- /package/{esm → dist/esm}/run.js +0 -0
- /package/{esm → dist/esm}/server.js +0 -0
- /package/{esm → dist/esm}/storage-multi.js +0 -0
- /package/{esm → dist/esm}/tao.js +0 -0
- /package/{esm → dist/esm}/tar.js +0 -0
- /package/{esm → dist/esm}/test.js +0 -0
- /package/{esm → dist/esm}/tgql-d1.js +0 -0
- /package/{esm → dist/esm}/tgql.js +0 -0
- /package/{esm → dist/esm}/toerl.js +0 -0
- /package/{esm → dist/esm}/utils.js +0 -0
- /package/{esm → dist/esm}/wao.js +0 -0
- /package/{esm → dist/esm}/waosm/README.md +0 -0
- /package/{esm → dist/esm}/waosm/waosm.d.ts +0 -0
- /package/{esm → dist/esm}/waosm/waosm.js +0 -0
- /package/{esm → dist/esm}/waosm/waosm_bg.wasm +0 -0
- /package/{esm → dist/esm}/waosm/waosm_bg.wasm.d.ts +0 -0
- /package/{esm → dist/esm}/waosm-node/README.md +0 -0
- /package/{esm → dist/esm}/waosm-node/waosm.d.ts +0 -0
- /package/{esm → dist/esm}/waosm-node/waosm.js +0 -0
- /package/{esm → dist/esm}/waosm-node/waosm_bg.js +0 -0
- /package/{esm → dist/esm}/waosm-node/waosm_bg.wasm +0 -0
- /package/{esm → dist/esm}/waosm-node/waosm_bg.wasm.d.ts +0 -0
- /package/{esm → dist/esm}/waosm-node/waosm_bg.wasm.js +0 -0
- /package/{esm → dist/esm}/waosm-node.js +0 -0
- /package/{esm → dist/esm}/war.js +0 -0
- /package/{esm → dist/esm}/weavedrive.js +0 -0
- /package/{esm → dist/esm}/web.js +0 -0
- /package/{esm → dist/esm}/workspace/.mcp.json +0 -0
- /package/{esm → dist/esm}/workspace/CLAUDE.md +0 -0
- /package/{esm → dist/esm}/workspace/README.md +0 -0
- /package/{esm → dist/esm}/workspace/dashboard/index.html +0 -0
- /package/{esm → dist/esm}/workspace/dashboard/package.json +0 -0
- /package/{esm/workspace/dashboard/public/favicon.png → dist/esm/workspace/dashboard/public/favicon.ico} +0 -0
- /package/{esm → dist/esm}/workspace/dashboard/server.js +0 -0
- /package/{esm → dist/esm}/workspace/dashboard/src/App.jsx +0 -0
- /package/{cjs/workspace/frontend → dist/esm/workspace/dashboard}/src/main.jsx +0 -0
- /package/{esm → dist/esm}/workspace/dashboard/vite.config.js +0 -0
- /package/{esm → dist/esm}/workspace/package.json +0 -0
- /package/{postinstall.cjs → dist/postinstall.cjs} +0 -0
- /package/{esm → src}/workspace/dashboard/src/main.jsx +0 -0
|
@@ -0,0 +1,1473 @@
|
|
|
1
|
+
import { queryTxs, queryBlocks, getResults, getResult, getTxData } from "../api.js"
|
|
2
|
+
import { table } from "../components/table.js"
|
|
3
|
+
import { renderTags } from "../components/tags.js"
|
|
4
|
+
import { navigate, trackBlobUrl } from "../router.js"
|
|
5
|
+
import { short, fromNow, tagsMap, formatDate, contentTypeLabel, typeBadgeClass, typeBadgeHtml } from "../utils.js"
|
|
6
|
+
|
|
7
|
+
export async function entityView(el, { id }) {
|
|
8
|
+
el.innerHTML = '<div class="loading">Loading...</div>'
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
if (/^\d+$/.test(id)) {
|
|
12
|
+
await renderBlock(el, parseInt(id))
|
|
13
|
+
return
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let data = await queryTxs({ ids: [id] })
|
|
17
|
+
let edge = data?.edges?.[0]
|
|
18
|
+
|
|
19
|
+
// Retry once — GQL index may not have caught up yet
|
|
20
|
+
if (!edge) {
|
|
21
|
+
await new Promise(r => setTimeout(r, 500))
|
|
22
|
+
data = await queryTxs({ ids: [id] })
|
|
23
|
+
edge = data?.edges?.[0]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!edge) {
|
|
27
|
+
const blocks = await queryBlocks({ first: 1 })
|
|
28
|
+
const found = blocks?.edges?.find((e) => e.node.id === id)
|
|
29
|
+
if (found) {
|
|
30
|
+
await renderBlockNode(el, found.node)
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const ownerTxs = await queryTxs({ owners: [id], first: 50 })
|
|
35
|
+
if (ownerTxs?.edges?.length) {
|
|
36
|
+
await renderAddress(el, id, ownerTxs)
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
el.innerHTML = `<div class="loading">Entity not found: ${short(id)}</div>`
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const node = edge.node
|
|
45
|
+
const tags = tagsMap(node.tags)
|
|
46
|
+
const type = tags["Type"] || "Transaction"
|
|
47
|
+
|
|
48
|
+
if (type === "Process") {
|
|
49
|
+
await renderProcess(el, node, tags)
|
|
50
|
+
} else if (type === "Message") {
|
|
51
|
+
await renderMessage(el, node, tags)
|
|
52
|
+
} else if (type === "Module") {
|
|
53
|
+
await renderModule(el, node, tags)
|
|
54
|
+
} else {
|
|
55
|
+
await renderGeneric(el, node, tags, type)
|
|
56
|
+
}
|
|
57
|
+
} catch (err) {
|
|
58
|
+
el.innerHTML = `<div class="loading">Error: ${err.message}</div>`
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ---- helpers ----
|
|
63
|
+
|
|
64
|
+
function detailHeader(type, id, name) {
|
|
65
|
+
const div = document.createElement("div")
|
|
66
|
+
div.className = "detail-header"
|
|
67
|
+
let html = `<span class="${typeBadgeClass(type)}">${type}</span>`
|
|
68
|
+
if (name) html += `<div class="entity-name">${name}</div>`
|
|
69
|
+
html += `<div class="entity-id"><h2>${id}</h2><button class="copy-btn" title="Copy to clipboard"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg></button></div>`
|
|
70
|
+
div.innerHTML = html
|
|
71
|
+
const copyBtn = div.querySelector(".copy-btn")
|
|
72
|
+
copyBtn.addEventListener("click", async () => {
|
|
73
|
+
try {
|
|
74
|
+
await navigator.clipboard.writeText(id)
|
|
75
|
+
copyBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>'
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
copyBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg>'
|
|
78
|
+
}, 1500)
|
|
79
|
+
} catch {}
|
|
80
|
+
})
|
|
81
|
+
return div
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function detailFields(fields) {
|
|
85
|
+
const div = document.createElement("div")
|
|
86
|
+
div.className = "detail-fields"
|
|
87
|
+
for (const [key, value] of fields) {
|
|
88
|
+
const field = document.createElement("div")
|
|
89
|
+
field.className = "field"
|
|
90
|
+
field.innerHTML = `<div class="field-key">${key}</div><div class="field-value">${value ?? "\u2014"}</div>`
|
|
91
|
+
div.appendChild(field)
|
|
92
|
+
}
|
|
93
|
+
return div
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function link(text, target) {
|
|
97
|
+
return `<span class="link mono" onclick="location.hash='#/entity/${target}'">${text}</span>`
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function msgTable(edges) {
|
|
101
|
+
const rows = edges.map((e) => {
|
|
102
|
+
const mt = tagsMap(e.node.tags)
|
|
103
|
+
return {
|
|
104
|
+
action: mt["Action"] || "\u2014",
|
|
105
|
+
id: e.node.id,
|
|
106
|
+
from: e.node.owner?.address || "\u2014",
|
|
107
|
+
to: e.node.recipient || "\u2014",
|
|
108
|
+
block: e.node.block?.height ?? "\u2014",
|
|
109
|
+
time: fromNow(e.node.block?.timestamp),
|
|
110
|
+
_id: e.node.id,
|
|
111
|
+
_from: e.node.owner?.address || "",
|
|
112
|
+
_to: e.node.recipient || "",
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
return table(
|
|
116
|
+
[
|
|
117
|
+
{ key: "action", label: "Action", render: (v) => `<span class="type-badge-message">${v}</span>` },
|
|
118
|
+
{ key: "id", label: "ID", mono: true, render: (v) => `<span class="link">${short(v)}</span>` },
|
|
119
|
+
{ key: "from", label: "From", mono: true, render: (v, r) => r._from ? `<span class="link" onclick="event.stopPropagation();location.hash='#/entity/${r._from}'">${short(v)}</span>` : v },
|
|
120
|
+
{ key: "to", label: "To", mono: true, render: (v, r) => r._to ? `<span class="link" onclick="event.stopPropagation();location.hash='#/entity/${r._to}'">${short(v)}</span>` : v },
|
|
121
|
+
{ key: "block", label: "Block" },
|
|
122
|
+
{ key: "time", label: "Time" },
|
|
123
|
+
],
|
|
124
|
+
rows,
|
|
125
|
+
(row) => navigate("#/entity/" + row._id),
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function section(title, content) {
|
|
130
|
+
const div = document.createElement("div")
|
|
131
|
+
div.className = "section"
|
|
132
|
+
div.innerHTML = `<div class="section-title">${title}</div>`
|
|
133
|
+
if (typeof content === "string") {
|
|
134
|
+
div.innerHTML += content
|
|
135
|
+
} else if (content) {
|
|
136
|
+
div.appendChild(content)
|
|
137
|
+
}
|
|
138
|
+
return div
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function twoCol(header, fields, tagsEl) {
|
|
142
|
+
const grid = document.createElement("div")
|
|
143
|
+
grid.className = "detail-grid"
|
|
144
|
+
const left = document.createElement("div")
|
|
145
|
+
left.appendChild(header)
|
|
146
|
+
left.appendChild(fields)
|
|
147
|
+
grid.appendChild(left)
|
|
148
|
+
grid.appendChild(tagsEl)
|
|
149
|
+
return grid
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ---- tabs ----
|
|
153
|
+
|
|
154
|
+
function createTabs(tabs) {
|
|
155
|
+
const wrap = document.createElement("div")
|
|
156
|
+
wrap.className = "entity-tabs"
|
|
157
|
+
|
|
158
|
+
const tabBar = document.createElement("div")
|
|
159
|
+
tabBar.className = "tab-bar"
|
|
160
|
+
|
|
161
|
+
const tabContent = document.createElement("div")
|
|
162
|
+
tabContent.className = "tab-content"
|
|
163
|
+
|
|
164
|
+
tabs.forEach((t, i) => {
|
|
165
|
+
const btn = document.createElement("button")
|
|
166
|
+
btn.className = "tab-btn" + (i === 0 ? " active" : "")
|
|
167
|
+
btn.textContent = t.label + (t.count != null ? ` (${t.count})` : "")
|
|
168
|
+
btn.addEventListener("click", () => {
|
|
169
|
+
tabBar.querySelectorAll(".tab-btn").forEach((b) => b.classList.remove("active"))
|
|
170
|
+
btn.classList.add("active")
|
|
171
|
+
tabContent.innerHTML = ""
|
|
172
|
+
if (typeof t.render === "function") {
|
|
173
|
+
const result = t.render()
|
|
174
|
+
if (result instanceof Node) tabContent.appendChild(result)
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
tabBar.appendChild(btn)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
wrap.appendChild(tabBar)
|
|
181
|
+
wrap.appendChild(tabContent)
|
|
182
|
+
|
|
183
|
+
// render first tab
|
|
184
|
+
if (tabs.length && typeof tabs[0].render === "function") {
|
|
185
|
+
const result = tabs[0].render()
|
|
186
|
+
if (result instanceof Node) tabContent.appendChild(result)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return wrap
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ---- Message tree ----
|
|
193
|
+
|
|
194
|
+
function renderMessageTree(parentNode, parentTags, childMsgs, computeResult, pushedForId, parentAction) {
|
|
195
|
+
const tree = document.createElement("div")
|
|
196
|
+
tree.className = "msg-tree"
|
|
197
|
+
|
|
198
|
+
const target = parentNode.recipient || parentTags["Target"] || ""
|
|
199
|
+
const arrowSvg = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>'
|
|
200
|
+
|
|
201
|
+
// When parent exists, all nodes (current + children) go in one continuous tree-children
|
|
202
|
+
let childWrap
|
|
203
|
+
|
|
204
|
+
if (pushedForId) {
|
|
205
|
+
// Level 1: parent node
|
|
206
|
+
const ancestor = document.createElement("div")
|
|
207
|
+
ancestor.className = "tree-node tree-root"
|
|
208
|
+
ancestor.innerHTML = `<div class="tree-node-header">
|
|
209
|
+
<span class="tree-node-dot root"></span>
|
|
210
|
+
${parentAction ? `<span class="type-badge-message">${parentAction}</span>` : ""}
|
|
211
|
+
<span class="mono link tree-node-id" onclick="location.hash='#/entity/${pushedForId}'">${pushedForId}</span>
|
|
212
|
+
</div>`
|
|
213
|
+
tree.appendChild(ancestor)
|
|
214
|
+
|
|
215
|
+
// Level 2: current message nested under parent
|
|
216
|
+
const level2 = document.createElement("div")
|
|
217
|
+
level2.className = "tree-children"
|
|
218
|
+
let selfHtml = `<div class="tree-child"><div class="tree-connector"></div><div class="tree-node-header">
|
|
219
|
+
<span class="tree-node-dot child" style="background:#4ade80;box-shadow:0 0 0 3px #1a3a2a"></span>
|
|
220
|
+
<span class="type-badge-message">${parentTags["Action"] || "Message"}</span>
|
|
221
|
+
<span class="mono tree-node-id">${parentNode.id}</span>`
|
|
222
|
+
if (target) {
|
|
223
|
+
selfHtml += `<span class="tree-node-arrow">${arrowSvg}</span>
|
|
224
|
+
<span class="mono link" onclick="location.hash='#/entity/${target}'">${target}</span>`
|
|
225
|
+
}
|
|
226
|
+
selfHtml += `</div></div>`
|
|
227
|
+
level2.innerHTML = selfHtml
|
|
228
|
+
tree.appendChild(level2)
|
|
229
|
+
|
|
230
|
+
// Level 3: children of the current message, nested one level deeper
|
|
231
|
+
childWrap = document.createElement("div")
|
|
232
|
+
childWrap.className = "tree-children"
|
|
233
|
+
childWrap.style.marginLeft = "24px"
|
|
234
|
+
level2.appendChild(childWrap)
|
|
235
|
+
} else {
|
|
236
|
+
// No parent — this message is the root (self = green)
|
|
237
|
+
const rootItem = document.createElement("div")
|
|
238
|
+
rootItem.className = "tree-node tree-root"
|
|
239
|
+
let rootHtml = `<div class="tree-node-header">
|
|
240
|
+
<span class="tree-node-dot root" style="background:#4ade80;box-shadow:0 0 0 3px #1a3a2a"></span>
|
|
241
|
+
<span class="type-badge-message">${parentTags["Action"] || "Message"}</span>
|
|
242
|
+
<span class="mono tree-node-id">${parentNode.id}</span>`
|
|
243
|
+
if (target) {
|
|
244
|
+
rootHtml += `<span class="tree-node-arrow">${arrowSvg}</span>
|
|
245
|
+
<span class="mono link" onclick="location.hash='#/entity/${target}'">${target}</span>`
|
|
246
|
+
}
|
|
247
|
+
rootHtml += `</div>`
|
|
248
|
+
rootItem.innerHTML = rootHtml
|
|
249
|
+
tree.appendChild(rootItem)
|
|
250
|
+
|
|
251
|
+
// Children container
|
|
252
|
+
childWrap = document.createElement("div")
|
|
253
|
+
childWrap.className = "tree-children"
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Show compute result replies first, then recorded GraphQL children (deduplicated).
|
|
257
|
+
const gqlChildren = childMsgs || []
|
|
258
|
+
const resultMsgs = computeResult?.Messages || []
|
|
259
|
+
|
|
260
|
+
// Track reply targets+actions to dedup GraphQL children
|
|
261
|
+
const replyKeys = new Set()
|
|
262
|
+
|
|
263
|
+
// 1. Compute result Messages — always show (replies/unrecorded)
|
|
264
|
+
for (const m of resultMsgs) {
|
|
265
|
+
const mt = tagsMap(m.Tags || m.tags)
|
|
266
|
+
const t = m.Target || m.target || ""
|
|
267
|
+
const action = mt["Action"] || "Message"
|
|
268
|
+
replyKeys.add(`${action}:${t}`)
|
|
269
|
+
const child = document.createElement("div")
|
|
270
|
+
child.className = "tree-node tree-child"
|
|
271
|
+
child.innerHTML = `
|
|
272
|
+
<div class="tree-connector"></div>
|
|
273
|
+
<div class="tree-node-header">
|
|
274
|
+
<span class="tree-node-dot child"></span>
|
|
275
|
+
<span class="type-badge-message">${action}</span>
|
|
276
|
+
<span class="tree-note">(reply)</span>
|
|
277
|
+
${t ? `<span class="tree-node-arrow">${arrowSvg}</span>
|
|
278
|
+
<span class="mono link" onclick="event.stopPropagation();location.hash='#/entity/${t}'">${t}</span>` : ""}
|
|
279
|
+
</div>
|
|
280
|
+
`
|
|
281
|
+
childWrap.appendChild(child)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// 2. GraphQL children (Pushed-For) — skip if already shown as reply
|
|
285
|
+
for (const edge of gqlChildren) {
|
|
286
|
+
const mt = tagsMap(edge.node.tags)
|
|
287
|
+
const action = mt["Action"] || "Message"
|
|
288
|
+
const recipient = edge.node.recipient || ""
|
|
289
|
+
if (replyKeys.has(`${action}:${recipient}`)) continue
|
|
290
|
+
const child = document.createElement("div")
|
|
291
|
+
child.className = "tree-node tree-child"
|
|
292
|
+
child.innerHTML = `
|
|
293
|
+
<div class="tree-connector"></div>
|
|
294
|
+
<div class="tree-node-header">
|
|
295
|
+
<span class="tree-node-dot child"></span>
|
|
296
|
+
<span class="type-badge-message">${action}</span>
|
|
297
|
+
<span class="mono link tree-node-id" onclick="event.stopPropagation();location.hash='#/entity/${edge.node.id}'">${edge.node.id}</span>
|
|
298
|
+
${recipient ? `<span class="tree-node-arrow">${arrowSvg}</span>
|
|
299
|
+
<span class="mono link" onclick="event.stopPropagation();location.hash='#/entity/${recipient}'">${recipient}</span>` : ""}
|
|
300
|
+
</div>
|
|
301
|
+
`
|
|
302
|
+
childWrap.appendChild(child)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Spawns
|
|
306
|
+
for (const s of computeResult?.Spawns || []) {
|
|
307
|
+
const st = tagsMap(s.Tags || s.tags)
|
|
308
|
+
const child = document.createElement("div")
|
|
309
|
+
child.className = "tree-node tree-child"
|
|
310
|
+
child.innerHTML = `
|
|
311
|
+
<div class="tree-connector"></div>
|
|
312
|
+
<div class="tree-node-header">
|
|
313
|
+
<span class="tree-node-dot spawn"></span>
|
|
314
|
+
<span class="type-badge-process">Spawn</span>
|
|
315
|
+
<span class="tree-node-name">${st["Name"] || "Process"}</span>
|
|
316
|
+
</div>
|
|
317
|
+
`
|
|
318
|
+
childWrap.appendChild(child)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (!childWrap.children.length) {
|
|
322
|
+
const leaf = document.createElement("div")
|
|
323
|
+
leaf.className = "tree-leaf"
|
|
324
|
+
leaf.textContent = "No child messages"
|
|
325
|
+
childWrap.appendChild(leaf)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// For no-parent case, childWrap needs to be appended to the tree
|
|
329
|
+
// For parent case, childWrap is already nested inside currentNode
|
|
330
|
+
if (!pushedForId) {
|
|
331
|
+
tree.appendChild(childWrap)
|
|
332
|
+
}
|
|
333
|
+
return tree
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ---- Process ----
|
|
337
|
+
|
|
338
|
+
async function renderProcess(el, node, tags) {
|
|
339
|
+
el.innerHTML = ""
|
|
340
|
+
const name = tags["Name"] || null
|
|
341
|
+
const header = detailHeader("Process", node.id, name)
|
|
342
|
+
const fields = detailFields([
|
|
343
|
+
["Owner", link(node.owner?.address, node.owner?.address)],
|
|
344
|
+
["Module", tags["Module"] ? link(tags["Module"], tags["Module"]) : "\u2014"],
|
|
345
|
+
["Name", tags["Name"] || "\u2014"],
|
|
346
|
+
["Scheduler", tags["Scheduler"] || "\u2014"],
|
|
347
|
+
["Block", node.block?.height ?? "\u2014"],
|
|
348
|
+
["Timestamp", formatDate(node.block?.timestamp)],
|
|
349
|
+
])
|
|
350
|
+
el.appendChild(twoCol(header, fields, section("Tags", renderTags(node.tags))))
|
|
351
|
+
|
|
352
|
+
// Source (Eval Lua script)
|
|
353
|
+
if (parseInt(node.data?.size || "0") > 0) {
|
|
354
|
+
const srcSection = document.createElement("div")
|
|
355
|
+
srcSection.className = "section"
|
|
356
|
+
srcSection.innerHTML = '<div class="section-title">Source</div>'
|
|
357
|
+
el.appendChild(srcSection)
|
|
358
|
+
renderDataViewer(srcSection, node.id, null, node)
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Fetch incoming and outgoing messages for this process
|
|
362
|
+
const [incoming, outgoing] = await Promise.all([
|
|
363
|
+
queryTxs({ first: 50, recipients: [node.id], tags: [{ name: "Type", values: ["Message"] }], sort: "HEIGHT_DESC" }).catch(() => null),
|
|
364
|
+
queryTxs({ first: 50, tags: [{ name: "Type", values: ["Message"] }, { name: "From-Process", values: [node.id] }], sort: "HEIGHT_DESC" }).catch(() => null),
|
|
365
|
+
])
|
|
366
|
+
|
|
367
|
+
const inEdges = incoming?.edges || []
|
|
368
|
+
const outEdges = outgoing?.edges || []
|
|
369
|
+
|
|
370
|
+
// All messages combined, deduped, sorted descending by block height
|
|
371
|
+
const allIds = new Set()
|
|
372
|
+
const allEdges = []
|
|
373
|
+
for (const e of [...inEdges, ...outEdges]) {
|
|
374
|
+
if (!allIds.has(e.node.id)) {
|
|
375
|
+
allIds.add(e.node.id)
|
|
376
|
+
allEdges.push(e)
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
allEdges.sort((a, b) => (b.node.block?.height ?? 0) - (a.node.block?.height ?? 0))
|
|
380
|
+
|
|
381
|
+
// Filter eval messages from incoming
|
|
382
|
+
const evalEdges = inEdges.filter((e) => {
|
|
383
|
+
const mt = tagsMap(e.node.tags)
|
|
384
|
+
return mt["Action"] === "Eval"
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
if (allEdges.length || evalEdges.length) {
|
|
388
|
+
const tabs = [
|
|
389
|
+
{ label: "All Messages", count: allEdges.length, render: () => msgTable(allEdges) },
|
|
390
|
+
{ label: "Incoming", count: inEdges.length, render: () => msgTable(inEdges) },
|
|
391
|
+
{ label: "Outgoing", count: outEdges.length, render: () => msgTable(outEdges) },
|
|
392
|
+
]
|
|
393
|
+
if (evalEdges.length) {
|
|
394
|
+
tabs.push({
|
|
395
|
+
label: "Eval",
|
|
396
|
+
count: evalEdges.length,
|
|
397
|
+
render: () => renderEvalList(evalEdges),
|
|
398
|
+
})
|
|
399
|
+
}
|
|
400
|
+
el.appendChild(createTabs(tabs))
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function renderEvalList(edges) {
|
|
405
|
+
const wrap = document.createElement("div")
|
|
406
|
+
for (const e of edges) {
|
|
407
|
+
const item = document.createElement("div")
|
|
408
|
+
item.className = "eval-item"
|
|
409
|
+
const header = document.createElement("div")
|
|
410
|
+
header.className = "eval-header"
|
|
411
|
+
header.innerHTML = `
|
|
412
|
+
<span class="mono link" onclick="location.hash='#/entity/${e.node.id}'">${short(e.node.id)}</span>
|
|
413
|
+
<span class="eval-from">from ${short(e.node.owner?.address || "")}</span>
|
|
414
|
+
<span class="eval-time">${fromNow(e.node.block?.timestamp)}</span>
|
|
415
|
+
`
|
|
416
|
+
item.appendChild(header)
|
|
417
|
+
|
|
418
|
+
const codeWrap = document.createElement("div")
|
|
419
|
+
codeWrap.innerHTML = '<pre class="code-block-body" style="margin-top:8px"><code>Loading...</code></pre>'
|
|
420
|
+
item.appendChild(codeWrap)
|
|
421
|
+
|
|
422
|
+
// Load the Lua source async with highlighting + copy btn on header
|
|
423
|
+
getTxData(e.node.id).then((data) => {
|
|
424
|
+
const src = data?.text || "-- (empty)"
|
|
425
|
+
codeWrap.innerHTML = ""
|
|
426
|
+
codeWrap.appendChild(buildCodeBody(src))
|
|
427
|
+
header.appendChild(makeCopyBtn(src))
|
|
428
|
+
}).catch(() => {
|
|
429
|
+
codeWrap.innerHTML = '<pre class="code-block-body" style="margin-top:8px"><code>-- (failed to load)</code></pre>'
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
wrap.appendChild(item)
|
|
433
|
+
}
|
|
434
|
+
return wrap
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// ---- Compute result with caching ----
|
|
438
|
+
|
|
439
|
+
function cacheKey(mid) { return `cu:${mid}` }
|
|
440
|
+
|
|
441
|
+
function getCachedResult(mid) {
|
|
442
|
+
try {
|
|
443
|
+
const raw = sessionStorage.getItem(cacheKey(mid))
|
|
444
|
+
return raw ? JSON.parse(raw) : null
|
|
445
|
+
} catch { return null }
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function setCachedResult(mid, result) {
|
|
449
|
+
try { sessionStorage.setItem(cacheKey(mid), JSON.stringify(result)) } catch {}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const ANSI_COLORS = {
|
|
453
|
+
"30": "#666", "31": "#e06c75", "32": "#98c379", "33": "#e5c07b",
|
|
454
|
+
"34": "#61afef", "35": "#c678dd", "36": "#56b6c2", "37": "#abb2bf",
|
|
455
|
+
"90": "#5c6370", "91": "#e06c75", "92": "#98c379", "93": "#e5c07b",
|
|
456
|
+
"94": "#61afef", "95": "#c678dd", "96": "#56b6c2", "97": "#ffffff",
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function ansiToHtml(text) {
|
|
460
|
+
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
|
461
|
+
let html = ""
|
|
462
|
+
let last = 0
|
|
463
|
+
// eslint-disable-next-line no-control-regex
|
|
464
|
+
const re = /\x1b\[([0-9;]*)m/g
|
|
465
|
+
let m
|
|
466
|
+
while ((m = re.exec(text)) !== null) {
|
|
467
|
+
html += esc(text.slice(last, m.index))
|
|
468
|
+
last = m.index + m[0].length
|
|
469
|
+
const codes = m[1]
|
|
470
|
+
if (!codes || codes === "0") {
|
|
471
|
+
html += "</span>"
|
|
472
|
+
} else {
|
|
473
|
+
for (const c of codes.split(";")) {
|
|
474
|
+
if (ANSI_COLORS[c]) html += `<span style="color:${ANSI_COLORS[c]}">`
|
|
475
|
+
else if (c === "1") html += '<span style="font-weight:bold">'
|
|
476
|
+
else if (c === "2") html += '<span style="opacity:0.7">'
|
|
477
|
+
else if (c === "3") html += '<span style="font-style:italic">'
|
|
478
|
+
else if (c === "4") html += '<span style="text-decoration:underline">'
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
html += esc(text.slice(last))
|
|
483
|
+
return html
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function renderAnsiText(text) {
|
|
487
|
+
const div = document.createElement("div")
|
|
488
|
+
// Check if text contains ANSI escape codes
|
|
489
|
+
// eslint-disable-next-line no-control-regex
|
|
490
|
+
if (/\x1b\[/.test(text)) {
|
|
491
|
+
div.innerHTML = ansiToHtml(text)
|
|
492
|
+
} else {
|
|
493
|
+
div.textContent = text
|
|
494
|
+
}
|
|
495
|
+
return div
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function renderComputeOutput(container, result) {
|
|
499
|
+
if (!result || (!result.Output?.data && !result.Messages?.length && !result.Spawns?.length)) {
|
|
500
|
+
const empty = document.createElement("div")
|
|
501
|
+
empty.className = "loading"
|
|
502
|
+
empty.style.padding = "16px"
|
|
503
|
+
empty.textContent = "No compute result available"
|
|
504
|
+
container.appendChild(empty)
|
|
505
|
+
return
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
if (result.Output?.data) {
|
|
509
|
+
const label = document.createElement("div")
|
|
510
|
+
label.className = "result-label"
|
|
511
|
+
label.textContent = "Output"
|
|
512
|
+
container.appendChild(label)
|
|
513
|
+
const out = document.createElement("div")
|
|
514
|
+
out.className = "result-output"
|
|
515
|
+
const raw = typeof result.Output.data === "string"
|
|
516
|
+
? result.Output.data
|
|
517
|
+
: JSON.stringify(result.Output.data, null, 2)
|
|
518
|
+
const rendered = renderAnsiText(raw)
|
|
519
|
+
out.appendChild(rendered)
|
|
520
|
+
container.appendChild(out)
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
if (result.Messages?.length) {
|
|
524
|
+
const label = document.createElement("div")
|
|
525
|
+
label.className = "section-title"
|
|
526
|
+
label.textContent = `Spawned Messages (${result.Messages.length})`
|
|
527
|
+
label.style.marginTop = "16px"
|
|
528
|
+
container.appendChild(label)
|
|
529
|
+
const rows = result.Messages.map((m, i) => {
|
|
530
|
+
const mt = tagsMap(m.Tags || m.tags)
|
|
531
|
+
return {
|
|
532
|
+
idx: i + 1,
|
|
533
|
+
action: mt["Action"] || "\u2014",
|
|
534
|
+
target: m.Target || m.target || "\u2014",
|
|
535
|
+
_target: m.Target || m.target || "",
|
|
536
|
+
}
|
|
537
|
+
})
|
|
538
|
+
container.appendChild(table(
|
|
539
|
+
[
|
|
540
|
+
{ key: "idx", label: "#" },
|
|
541
|
+
{ key: "action", label: "Action" },
|
|
542
|
+
{ key: "target", label: "Target", mono: true, render: (v, r) => r._target ? `<span class="link" onclick="event.stopPropagation();location.hash='#/entity/${r._target}'">${short(v)}</span>` : v },
|
|
543
|
+
],
|
|
544
|
+
rows,
|
|
545
|
+
))
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (result.Spawns?.length) {
|
|
549
|
+
const label = document.createElement("div")
|
|
550
|
+
label.className = "section-title"
|
|
551
|
+
label.textContent = `Spawns (${result.Spawns.length})`
|
|
552
|
+
label.style.marginTop = "16px"
|
|
553
|
+
container.appendChild(label)
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function highlightLua(code) {
|
|
558
|
+
const keywords = new Set(["and","break","do","else","elseif","end","false","for","function","if","in","local","nil","not","or","repeat","return","then","true","until","while"])
|
|
559
|
+
const builtins = new Set(["print","tostring","tonumber","type","pairs","ipairs","require","error","pcall","xpcall","assert","select","unpack","table","string","math","io","os","ao","Handlers","Send","Spawn","msg"])
|
|
560
|
+
// Escape HTML
|
|
561
|
+
const esc = s => s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")
|
|
562
|
+
// Tokenize and highlight
|
|
563
|
+
return code.replace(/--\[\[[\s\S]*?\]\]|--[^\n]*|"[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*'|\[\[[\s\S]*?\]\]|\b\d+\.?\d*\b|[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*|[^\s]/g, token => {
|
|
564
|
+
if (token.startsWith("--")) return `<span class="lua-comment">${esc(token)}</span>`
|
|
565
|
+
if (token.startsWith('"') || token.startsWith("'") || token.startsWith("[[")) return `<span class="lua-string">${esc(token)}</span>`
|
|
566
|
+
if (/^\d/.test(token)) return `<span class="lua-number">${esc(token)}</span>`
|
|
567
|
+
if (/^[A-Za-z_]/.test(token)) {
|
|
568
|
+
// Handle dotted names like ao.send, Handlers.add
|
|
569
|
+
const parts = token.split(".")
|
|
570
|
+
return parts.map(p => {
|
|
571
|
+
if (keywords.has(p)) return `<span class="lua-keyword">${esc(p)}</span>`
|
|
572
|
+
if (builtins.has(p)) return `<span class="lua-builtin">${esc(p)}</span>`
|
|
573
|
+
return esc(p)
|
|
574
|
+
}).join(`<span class="lua-punct">.</span>`)
|
|
575
|
+
}
|
|
576
|
+
return esc(token)
|
|
577
|
+
})
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
const clipSvg = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'
|
|
581
|
+
const checkSvg = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#4ade80" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
|
|
582
|
+
|
|
583
|
+
function makeCopyBtn(text) {
|
|
584
|
+
const btn = document.createElement("button")
|
|
585
|
+
btn.className = "code-copy-btn"
|
|
586
|
+
btn.title = "Copy to clipboard"
|
|
587
|
+
btn.innerHTML = clipSvg
|
|
588
|
+
btn.onclick = () => {
|
|
589
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
590
|
+
btn.innerHTML = checkSvg
|
|
591
|
+
setTimeout(() => { btn.innerHTML = clipSvg }, 1500)
|
|
592
|
+
})
|
|
593
|
+
}
|
|
594
|
+
return btn
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function buildCodeBody(src) {
|
|
598
|
+
const wrap = document.createElement("div")
|
|
599
|
+
wrap.className = "code-block-body"
|
|
600
|
+
const lines = src.split("\n")
|
|
601
|
+
const gutter = document.createElement("pre")
|
|
602
|
+
gutter.className = "code-gutter"
|
|
603
|
+
gutter.textContent = lines.map((_, i) => i + 1).join("\n")
|
|
604
|
+
const code = document.createElement("pre")
|
|
605
|
+
code.className = "code-content"
|
|
606
|
+
code.innerHTML = highlightLua(src)
|
|
607
|
+
wrap.appendChild(gutter)
|
|
608
|
+
wrap.appendChild(code)
|
|
609
|
+
return wrap
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// ---- Simple markdown renderer ----
|
|
613
|
+
|
|
614
|
+
function renderMarkdown(text) {
|
|
615
|
+
const esc = s => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
|
616
|
+
const lines = text.split("\n")
|
|
617
|
+
let html = ""
|
|
618
|
+
let inCode = false
|
|
619
|
+
let inList = false
|
|
620
|
+
let listType = null
|
|
621
|
+
|
|
622
|
+
for (let i = 0; i < lines.length; i++) {
|
|
623
|
+
const line = lines[i]
|
|
624
|
+
|
|
625
|
+
// Fenced code blocks
|
|
626
|
+
if (line.trimStart().startsWith("```")) {
|
|
627
|
+
if (inCode) {
|
|
628
|
+
html += "</code></pre>"
|
|
629
|
+
inCode = false
|
|
630
|
+
} else {
|
|
631
|
+
if (inList) { html += listType === "ul" ? "</ul>" : "</ol>"; inList = false }
|
|
632
|
+
html += '<pre class="data-md-code"><code>'
|
|
633
|
+
inCode = true
|
|
634
|
+
}
|
|
635
|
+
continue
|
|
636
|
+
}
|
|
637
|
+
if (inCode) {
|
|
638
|
+
html += esc(line) + "\n"
|
|
639
|
+
continue
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// Close list if line is not a list item
|
|
643
|
+
if (inList && !/^\s*[-*]\s|^\s*\d+\.\s/.test(line) && line.trim() !== "") {
|
|
644
|
+
html += listType === "ul" ? "</ul>" : "</ol>"
|
|
645
|
+
inList = false
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// Blank line
|
|
649
|
+
if (line.trim() === "") {
|
|
650
|
+
if (inList) { html += listType === "ul" ? "</ul>" : "</ol>"; inList = false }
|
|
651
|
+
continue
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Headings
|
|
655
|
+
const hm = line.match(/^(#{1,6})\s+(.*)/)
|
|
656
|
+
if (hm) {
|
|
657
|
+
const level = hm[1].length
|
|
658
|
+
html += `<h${level}>${inlineFormat(esc(hm[2]))}</h${level}>`
|
|
659
|
+
continue
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// Unordered list
|
|
663
|
+
if (/^\s*[-*]\s/.test(line)) {
|
|
664
|
+
if (!inList || listType !== "ul") {
|
|
665
|
+
if (inList) html += listType === "ul" ? "</ul>" : "</ol>"
|
|
666
|
+
html += "<ul>"
|
|
667
|
+
inList = true
|
|
668
|
+
listType = "ul"
|
|
669
|
+
}
|
|
670
|
+
html += `<li>${inlineFormat(esc(line.replace(/^\s*[-*]\s/, "")))}</li>`
|
|
671
|
+
continue
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Ordered list
|
|
675
|
+
if (/^\s*\d+\.\s/.test(line)) {
|
|
676
|
+
if (!inList || listType !== "ol") {
|
|
677
|
+
if (inList) html += listType === "ul" ? "</ul>" : "</ol>"
|
|
678
|
+
html += "<ol>"
|
|
679
|
+
inList = true
|
|
680
|
+
listType = "ol"
|
|
681
|
+
}
|
|
682
|
+
html += `<li>${inlineFormat(esc(line.replace(/^\s*\d+\.\s/, "")))}</li>`
|
|
683
|
+
continue
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// Paragraph
|
|
687
|
+
html += `<p>${inlineFormat(esc(line))}</p>`
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
if (inCode) html += "</code></pre>"
|
|
691
|
+
if (inList) html += listType === "ul" ? "</ul>" : "</ol>"
|
|
692
|
+
return html
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
function inlineFormat(text) {
|
|
696
|
+
return text
|
|
697
|
+
.replace(/`([^`]+)`/g, "<code>$1</code>")
|
|
698
|
+
.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
|
|
699
|
+
.replace(/\*([^*]+)\*/g, "<em>$1</em>")
|
|
700
|
+
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>')
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// ---- Hex dump renderer ----
|
|
704
|
+
|
|
705
|
+
function renderHexDump(bytes) {
|
|
706
|
+
const view = new Uint8Array(bytes)
|
|
707
|
+
const limit = Math.min(view.length, 256)
|
|
708
|
+
let html = ""
|
|
709
|
+
for (let i = 0; i < limit; i += 16) {
|
|
710
|
+
const addr = i.toString(16).padStart(8, "0")
|
|
711
|
+
let hex = ""
|
|
712
|
+
let ascii = ""
|
|
713
|
+
for (let j = 0; j < 16; j++) {
|
|
714
|
+
if (i + j < limit) {
|
|
715
|
+
const b = view[i + j]
|
|
716
|
+
hex += b.toString(16).padStart(2, "0") + " "
|
|
717
|
+
ascii += b >= 0x20 && b <= 0x7e ? String.fromCharCode(b) : "."
|
|
718
|
+
} else {
|
|
719
|
+
hex += " "
|
|
720
|
+
ascii += " "
|
|
721
|
+
}
|
|
722
|
+
if (j === 7) hex += " "
|
|
723
|
+
}
|
|
724
|
+
html += `<div class="hex-row"><span class="hex-addr">${addr}</span><span class="hex-bytes">${hex}</span><span class="hex-ascii">${ascii}</span></div>`
|
|
725
|
+
}
|
|
726
|
+
if (view.length > limit) {
|
|
727
|
+
html += `<div class="hex-row hex-truncated">... ${view.length - limit} more bytes</div>`
|
|
728
|
+
}
|
|
729
|
+
return html
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// ---- JSON collapsible viewer ----
|
|
733
|
+
|
|
734
|
+
const JSON_MAX_DEPTH = 20
|
|
735
|
+
const JSON_MAX_KEYS = 200
|
|
736
|
+
|
|
737
|
+
function renderJsonTree(obj, depth = 0) {
|
|
738
|
+
if (depth > JSON_MAX_DEPTH) return '<span class="json-null">...</span>'
|
|
739
|
+
if (obj === null) return '<span class="json-null">null</span>'
|
|
740
|
+
if (typeof obj === "boolean") return `<span class="json-bool">${obj}</span>`
|
|
741
|
+
if (typeof obj === "number") return `<span class="json-number">${obj}</span>`
|
|
742
|
+
if (typeof obj === "string") {
|
|
743
|
+
const display = obj.length > 10000 ? obj.slice(0, 10000) + "..." : obj
|
|
744
|
+
const esc = display.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """)
|
|
745
|
+
return `<span class="json-string">"${esc}"</span>`
|
|
746
|
+
}
|
|
747
|
+
if (Array.isArray(obj)) {
|
|
748
|
+
if (obj.length === 0) return "[]"
|
|
749
|
+
const limited = obj.slice(0, JSON_MAX_KEYS)
|
|
750
|
+
const items = limited.map(v => `<div class="json-indent">${renderJsonTree(v, depth + 1)},</div>`).join("")
|
|
751
|
+
const truncated = obj.length > JSON_MAX_KEYS ? `<div class="json-indent"><span class="json-null">... ${obj.length - JSON_MAX_KEYS} more items</span></div>` : ""
|
|
752
|
+
return `[${items}${truncated}]`
|
|
753
|
+
}
|
|
754
|
+
if (typeof obj === "object") {
|
|
755
|
+
const keys = Object.keys(obj)
|
|
756
|
+
if (keys.length === 0) return "{}"
|
|
757
|
+
const limited = keys.slice(0, JSON_MAX_KEYS)
|
|
758
|
+
const items = limited.map(k => {
|
|
759
|
+
const esc = k.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """)
|
|
760
|
+
return `<div class="json-indent"><span class="json-key">"${esc}"</span>: ${renderJsonTree(obj[k], depth + 1)},</div>`
|
|
761
|
+
}).join("")
|
|
762
|
+
const truncated = keys.length > JSON_MAX_KEYS ? `<div class="json-indent"><span class="json-null">... ${keys.length - JSON_MAX_KEYS} more keys</span></div>` : ""
|
|
763
|
+
return `{${items}${truncated}}`
|
|
764
|
+
}
|
|
765
|
+
return String(obj)
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// ---- Data viewer header ----
|
|
769
|
+
|
|
770
|
+
function dataViewerHeader(contentType, size, blobUrl, filename, text) {
|
|
771
|
+
const header = document.createElement("div")
|
|
772
|
+
header.className = "data-viewer-header"
|
|
773
|
+
const badge = document.createElement("span")
|
|
774
|
+
badge.className = "data-ct-badge"
|
|
775
|
+
badge.textContent = contentType
|
|
776
|
+
header.appendChild(badge)
|
|
777
|
+
|
|
778
|
+
const sizeEl = document.createElement("span")
|
|
779
|
+
sizeEl.className = "data-size"
|
|
780
|
+
sizeEl.textContent = size < 1024 ? `${size} B` : size < 1048576 ? `${(size / 1024).toFixed(1)} KB` : `${(size / 1048576).toFixed(1)} MB`
|
|
781
|
+
header.appendChild(sizeEl)
|
|
782
|
+
|
|
783
|
+
const spacer = document.createElement("span")
|
|
784
|
+
spacer.style.flex = "1"
|
|
785
|
+
header.appendChild(spacer)
|
|
786
|
+
|
|
787
|
+
if (text !== null) {
|
|
788
|
+
header.appendChild(makeCopyBtn(text))
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const dlBtn = document.createElement("a")
|
|
792
|
+
dlBtn.className = "data-download-btn"
|
|
793
|
+
dlBtn.href = blobUrl
|
|
794
|
+
dlBtn.download = filename
|
|
795
|
+
dlBtn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> Download'
|
|
796
|
+
header.appendChild(dlBtn)
|
|
797
|
+
|
|
798
|
+
return header
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// ---- Rich data viewer (replaces autoLoadData) ----
|
|
802
|
+
|
|
803
|
+
async function renderDataViewer(container, txId, action, node) {
|
|
804
|
+
const loading = document.createElement("div")
|
|
805
|
+
loading.className = "loading"
|
|
806
|
+
loading.style.padding = "12px"
|
|
807
|
+
loading.textContent = "Loading data..."
|
|
808
|
+
container.appendChild(loading)
|
|
809
|
+
try {
|
|
810
|
+
const data = await getTxData(txId)
|
|
811
|
+
loading.remove()
|
|
812
|
+
if (!data) {
|
|
813
|
+
const empty = document.createElement("div")
|
|
814
|
+
empty.className = "data-preview"
|
|
815
|
+
empty.textContent = "No data"
|
|
816
|
+
container.appendChild(empty)
|
|
817
|
+
return
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
const { contentType, blob, text, size } = data
|
|
821
|
+
|
|
822
|
+
// Handle files too large for in-browser rendering
|
|
823
|
+
if (data.tooLarge) {
|
|
824
|
+
const info = document.createElement("div")
|
|
825
|
+
info.className = "data-viewer"
|
|
826
|
+
const sizeStr = size < 1048576 ? (size / 1024).toFixed(1) + " KB" : (size / 1048576).toFixed(1) + " MB"
|
|
827
|
+
info.innerHTML = `<div class="data-viewer-header"><span class="data-ct-badge">${contentType}</span><span class="data-size">${sizeStr}</span><span style="flex:1"></span><a class="data-download-btn" href="/ar/${txId}" download="${txId}"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> Download</a></div><div class="data-preview">File too large for in-browser preview (${sizeStr}). Use the download button.</div>`
|
|
828
|
+
container.appendChild(info)
|
|
829
|
+
return
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
const blobUrl = URL.createObjectURL(blob)
|
|
833
|
+
trackBlobUrl(blobUrl)
|
|
834
|
+
const viewer = document.createElement("div")
|
|
835
|
+
viewer.className = "data-viewer"
|
|
836
|
+
|
|
837
|
+
// Header with badge, size, buttons
|
|
838
|
+
viewer.appendChild(dataViewerHeader(contentType, size, blobUrl, txId, text))
|
|
839
|
+
|
|
840
|
+
// Dispatch on content type
|
|
841
|
+
if (action === "Eval" || contentType === "text/x-lua") {
|
|
842
|
+
// Lua code with syntax highlighting
|
|
843
|
+
viewer.appendChild(buildCodeBody(text || "-- (empty)"))
|
|
844
|
+
} else if (contentType.startsWith("image/svg+xml") && text) {
|
|
845
|
+
// SVG: render + toggle to code (sanitize scripts)
|
|
846
|
+
const btnGroup = document.createElement("div")
|
|
847
|
+
btnGroup.className = "data-view-tabs"
|
|
848
|
+
const btnPreview = document.createElement("button")
|
|
849
|
+
btnPreview.className = "data-view-tab active"
|
|
850
|
+
btnPreview.textContent = "Preview"
|
|
851
|
+
const btnSource = document.createElement("button")
|
|
852
|
+
btnSource.className = "data-view-tab"
|
|
853
|
+
btnSource.textContent = "Source"
|
|
854
|
+
btnGroup.appendChild(btnPreview)
|
|
855
|
+
btnGroup.appendChild(btnSource)
|
|
856
|
+
viewer.firstChild.insertBefore(btnGroup, viewer.firstChild.querySelector(".data-size").nextSibling)
|
|
857
|
+
|
|
858
|
+
const svgContainer = document.createElement("div")
|
|
859
|
+
svgContainer.className = "data-svg-wrap"
|
|
860
|
+
const svgRender = document.createElement("div")
|
|
861
|
+
svgRender.className = "data-svg-render"
|
|
862
|
+
const sanitizedSvg = text.replace(/<script[\s\S]*?<\/script>/gi, "").replace(/\bon\w+\s*=/gi, "data-removed=")
|
|
863
|
+
svgRender.innerHTML = sanitizedSvg
|
|
864
|
+
const codeView = document.createElement("div")
|
|
865
|
+
codeView.className = "data-svg-code"
|
|
866
|
+
codeView.style.display = "none"
|
|
867
|
+
codeView.appendChild(buildGenericCodeBody(text))
|
|
868
|
+
btnPreview.addEventListener("click", () => {
|
|
869
|
+
svgRender.style.display = ""
|
|
870
|
+
codeView.style.display = "none"
|
|
871
|
+
btnPreview.classList.add("active")
|
|
872
|
+
btnSource.classList.remove("active")
|
|
873
|
+
})
|
|
874
|
+
btnSource.addEventListener("click", () => {
|
|
875
|
+
svgRender.style.display = "none"
|
|
876
|
+
codeView.style.display = ""
|
|
877
|
+
btnSource.classList.add("active")
|
|
878
|
+
btnPreview.classList.remove("active")
|
|
879
|
+
})
|
|
880
|
+
svgContainer.appendChild(svgRender)
|
|
881
|
+
svgContainer.appendChild(codeView)
|
|
882
|
+
viewer.appendChild(svgContainer)
|
|
883
|
+
} else if (contentType.startsWith("image/")) {
|
|
884
|
+
const box = document.createElement("div")
|
|
885
|
+
box.className = "data-media-box"
|
|
886
|
+
const img = document.createElement("img")
|
|
887
|
+
img.className = "data-img"
|
|
888
|
+
img.src = blobUrl
|
|
889
|
+
img.alt = "Transaction data"
|
|
890
|
+
box.appendChild(img)
|
|
891
|
+
viewer.appendChild(box)
|
|
892
|
+
} else if (contentType.startsWith("video/")) {
|
|
893
|
+
const box = document.createElement("div")
|
|
894
|
+
box.className = "data-video-box"
|
|
895
|
+
const video = document.createElement("video")
|
|
896
|
+
video.className = "data-video"
|
|
897
|
+
video.src = blobUrl
|
|
898
|
+
video.controls = true
|
|
899
|
+
box.appendChild(video)
|
|
900
|
+
viewer.appendChild(box)
|
|
901
|
+
} else if (contentType.startsWith("audio/")) {
|
|
902
|
+
const audio = document.createElement("audio")
|
|
903
|
+
audio.src = blobUrl
|
|
904
|
+
audio.controls = true
|
|
905
|
+
audio.style.width = "100%"
|
|
906
|
+
viewer.appendChild(audio)
|
|
907
|
+
} else if (contentType === "text/markdown" && text) {
|
|
908
|
+
// Add view mode buttons to header
|
|
909
|
+
const btnGroup = document.createElement("div")
|
|
910
|
+
btnGroup.className = "data-view-tabs"
|
|
911
|
+
const btnPreview = document.createElement("button")
|
|
912
|
+
btnPreview.className = "data-view-tab active"
|
|
913
|
+
btnPreview.textContent = "Preview"
|
|
914
|
+
const btnSource = document.createElement("button")
|
|
915
|
+
btnSource.className = "data-view-tab"
|
|
916
|
+
btnSource.textContent = "Source"
|
|
917
|
+
btnGroup.appendChild(btnPreview)
|
|
918
|
+
btnGroup.appendChild(btnSource)
|
|
919
|
+
viewer.firstChild.insertBefore(btnGroup, viewer.firstChild.querySelector(".data-size").nextSibling)
|
|
920
|
+
|
|
921
|
+
const mdWrap = document.createElement("div")
|
|
922
|
+
mdWrap.className = "data-md-wrap"
|
|
923
|
+
const mdPreview = document.createElement("div")
|
|
924
|
+
mdPreview.className = "data-markdown"
|
|
925
|
+
mdPreview.innerHTML = renderMarkdown(text)
|
|
926
|
+
const mdCode = document.createElement("div")
|
|
927
|
+
mdCode.style.display = "none"
|
|
928
|
+
mdCode.appendChild(buildGenericCodeBody(text))
|
|
929
|
+
btnPreview.addEventListener("click", () => {
|
|
930
|
+
mdPreview.style.display = ""
|
|
931
|
+
mdCode.style.display = "none"
|
|
932
|
+
btnPreview.classList.add("active")
|
|
933
|
+
btnSource.classList.remove("active")
|
|
934
|
+
})
|
|
935
|
+
btnSource.addEventListener("click", () => {
|
|
936
|
+
mdPreview.style.display = "none"
|
|
937
|
+
mdCode.style.display = ""
|
|
938
|
+
btnSource.classList.add("active")
|
|
939
|
+
btnPreview.classList.remove("active")
|
|
940
|
+
})
|
|
941
|
+
mdWrap.appendChild(mdPreview)
|
|
942
|
+
mdWrap.appendChild(mdCode)
|
|
943
|
+
viewer.appendChild(mdWrap)
|
|
944
|
+
} else if (contentType === "text/html" && text) {
|
|
945
|
+
const iframe = document.createElement("iframe")
|
|
946
|
+
iframe.className = "data-html-frame"
|
|
947
|
+
iframe.sandbox = "allow-scripts"
|
|
948
|
+
iframe.srcdoc = text
|
|
949
|
+
viewer.appendChild(iframe)
|
|
950
|
+
} else if (contentType.includes("json") && text) {
|
|
951
|
+
try {
|
|
952
|
+
const obj = JSON.parse(text)
|
|
953
|
+
const pre = document.createElement("pre")
|
|
954
|
+
pre.className = "data-json"
|
|
955
|
+
pre.innerHTML = renderJsonTree(obj)
|
|
956
|
+
viewer.appendChild(pre)
|
|
957
|
+
} catch {
|
|
958
|
+
viewer.appendChild(buildGenericCodeBody(text))
|
|
959
|
+
}
|
|
960
|
+
} else if (
|
|
961
|
+
contentType.includes("javascript") || contentType.includes("typescript") ||
|
|
962
|
+
contentType.includes("ecmascript") || contentType.includes("css") ||
|
|
963
|
+
contentType.includes("x-python") || contentType.includes("python") ||
|
|
964
|
+
contentType.includes("x-toml") || contentType.includes("x-yaml") ||
|
|
965
|
+
contentType.includes("x-sh") || contentType.includes("shell") ||
|
|
966
|
+
contentType.includes("x-rust") || contentType.includes("x-go") ||
|
|
967
|
+
contentType.includes("x-c") || contentType.includes("x-java")
|
|
968
|
+
) {
|
|
969
|
+
viewer.appendChild(buildGenericCodeBody(text || "", contentType))
|
|
970
|
+
} else if (text !== null) {
|
|
971
|
+
// Fallback: plain text with ANSI support
|
|
972
|
+
const pre = document.createElement("div")
|
|
973
|
+
pre.className = "data-preview"
|
|
974
|
+
pre.appendChild(renderAnsiText(text))
|
|
975
|
+
viewer.appendChild(pre)
|
|
976
|
+
} else {
|
|
977
|
+
// Binary fallback — just show info, no hex dump
|
|
978
|
+
const info = document.createElement("div")
|
|
979
|
+
info.className = "data-preview"
|
|
980
|
+
info.textContent = `Binary data (${size < 1024 ? size + " bytes" : size < 1048576 ? (size / 1024).toFixed(1) + " KB" : (size / 1048576).toFixed(1) + " MB"})`
|
|
981
|
+
viewer.appendChild(info)
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
container.appendChild(viewer)
|
|
985
|
+
|
|
986
|
+
// Bundle items: if this tx has Bundle-Format tag, show child items
|
|
987
|
+
if (node) {
|
|
988
|
+
const tags = node.tags || []
|
|
989
|
+
const hasBundleFormat = tags.some(t => t.name === "Bundle-Format")
|
|
990
|
+
if (hasBundleFormat) {
|
|
991
|
+
await renderBundleItems(container, txId)
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
} catch {
|
|
995
|
+
loading.remove()
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// ---- Generic code body with syntax highlighting ----
|
|
1000
|
+
|
|
1001
|
+
function highlightGeneric(code, lang) {
|
|
1002
|
+
const esc = s => s.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")
|
|
1003
|
+
const kw = {
|
|
1004
|
+
js: ["const","let","var","function","return","if","else","for","while","do","switch","case","break","continue","new","this","class","extends","import","export","from","default","async","await","try","catch","throw","finally","typeof","instanceof","in","of","yield","delete","void","null","undefined","true","false","super","static","get","set"],
|
|
1005
|
+
py: ["def","class","return","if","elif","else","for","while","try","except","finally","with","as","import","from","raise","pass","break","continue","yield","lambda","and","or","not","in","is","True","False","None","global","nonlocal","assert","del","async","await"],
|
|
1006
|
+
css: ["@media","@keyframes","@import","@font-face","@charset","@supports","!important"],
|
|
1007
|
+
sh: ["if","then","else","elif","fi","for","while","do","done","case","esac","in","function","return","local","export","source","alias","echo","exit","read","set","unset","shift","trap","eval","exec","test"],
|
|
1008
|
+
toml: [],
|
|
1009
|
+
yaml: ["true","false","null","yes","no","on","off"],
|
|
1010
|
+
}
|
|
1011
|
+
const keywords = new Set(kw[lang] || kw.js)
|
|
1012
|
+
const lineComment = lang === "py" || lang === "sh" || lang === "toml" || lang === "yaml" ? "#" : "//"
|
|
1013
|
+
const hasBlock = lang === "js" || lang === "css"
|
|
1014
|
+
|
|
1015
|
+
let result = ""
|
|
1016
|
+
let i = 0
|
|
1017
|
+
while (i < code.length) {
|
|
1018
|
+
// Block comments
|
|
1019
|
+
if (hasBlock && code[i] === "/" && code[i+1] === "*") {
|
|
1020
|
+
const end = code.indexOf("*/", i + 2)
|
|
1021
|
+
const slice = end === -1 ? code.slice(i) : code.slice(i, end + 2)
|
|
1022
|
+
result += `<span class="lua-comment">${esc(slice)}</span>`
|
|
1023
|
+
i += slice.length
|
|
1024
|
+
continue
|
|
1025
|
+
}
|
|
1026
|
+
// Line comments
|
|
1027
|
+
if (code.slice(i, i + lineComment.length) === lineComment) {
|
|
1028
|
+
const nl = code.indexOf("\n", i)
|
|
1029
|
+
const slice = nl === -1 ? code.slice(i) : code.slice(i, nl)
|
|
1030
|
+
result += `<span class="lua-comment">${esc(slice)}</span>`
|
|
1031
|
+
i += slice.length
|
|
1032
|
+
continue
|
|
1033
|
+
}
|
|
1034
|
+
// Strings
|
|
1035
|
+
if (code[i] === '"' || code[i] === "'" || code[i] === "`") {
|
|
1036
|
+
const q = code[i]
|
|
1037
|
+
let j = i + 1
|
|
1038
|
+
while (j < code.length && code[j] !== q) {
|
|
1039
|
+
if (code[j] === "\\") j++
|
|
1040
|
+
j++
|
|
1041
|
+
}
|
|
1042
|
+
if (j < code.length) j++
|
|
1043
|
+
result += `<span class="lua-string">${esc(code.slice(i, j))}</span>`
|
|
1044
|
+
i = j
|
|
1045
|
+
continue
|
|
1046
|
+
}
|
|
1047
|
+
// Numbers
|
|
1048
|
+
if (/[0-9]/.test(code[i]) && (i === 0 || /[\s,;:({[=+\-*/%<>!&|^~?]/.test(code[i-1]))) {
|
|
1049
|
+
let j = i
|
|
1050
|
+
if (code[j] === "0" && (code[j+1] === "x" || code[j+1] === "X")) j += 2
|
|
1051
|
+
while (j < code.length && /[0-9a-fA-F._]/.test(code[j])) j++
|
|
1052
|
+
result += `<span class="lua-number">${esc(code.slice(i, j))}</span>`
|
|
1053
|
+
i = j
|
|
1054
|
+
continue
|
|
1055
|
+
}
|
|
1056
|
+
// Identifiers / keywords
|
|
1057
|
+
if (/[A-Za-z_$]/.test(code[i])) {
|
|
1058
|
+
let j = i
|
|
1059
|
+
while (j < code.length && /[A-Za-z0-9_$]/.test(code[j])) j++
|
|
1060
|
+
const word = code.slice(i, j)
|
|
1061
|
+
if (keywords.has(word)) {
|
|
1062
|
+
result += `<span class="lua-keyword">${esc(word)}</span>`
|
|
1063
|
+
} else {
|
|
1064
|
+
result += esc(word)
|
|
1065
|
+
}
|
|
1066
|
+
i = j
|
|
1067
|
+
continue
|
|
1068
|
+
}
|
|
1069
|
+
result += esc(code[i])
|
|
1070
|
+
i++
|
|
1071
|
+
}
|
|
1072
|
+
return result
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
function detectLang(contentType) {
|
|
1076
|
+
if (contentType.includes("javascript") || contentType.includes("ecmascript")) return "js"
|
|
1077
|
+
if (contentType.includes("typescript")) return "js"
|
|
1078
|
+
if (contentType.includes("python")) return "py"
|
|
1079
|
+
if (contentType.includes("css")) return "css"
|
|
1080
|
+
if (contentType.includes("x-sh") || contentType.includes("shell") || contentType.includes("bash")) return "sh"
|
|
1081
|
+
if (contentType.includes("toml")) return "toml"
|
|
1082
|
+
if (contentType.includes("yaml") || contentType.includes("yml")) return "yaml"
|
|
1083
|
+
if (contentType.includes("lua")) return "lua"
|
|
1084
|
+
return "js" // default fallback
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
function buildGenericCodeBody(src, contentType) {
|
|
1088
|
+
const wrap = document.createElement("div")
|
|
1089
|
+
wrap.className = "code-block-body"
|
|
1090
|
+
const lines = src.split("\n")
|
|
1091
|
+
const gutter = document.createElement("pre")
|
|
1092
|
+
gutter.className = "code-gutter"
|
|
1093
|
+
gutter.textContent = lines.map((_, i) => i + 1).join("\n")
|
|
1094
|
+
const code = document.createElement("pre")
|
|
1095
|
+
code.className = "code-content"
|
|
1096
|
+
if (contentType) {
|
|
1097
|
+
const lang = detectLang(contentType)
|
|
1098
|
+
if (lang === "lua") {
|
|
1099
|
+
code.innerHTML = highlightLua(src)
|
|
1100
|
+
} else {
|
|
1101
|
+
code.innerHTML = highlightGeneric(src, lang)
|
|
1102
|
+
}
|
|
1103
|
+
} else {
|
|
1104
|
+
code.textContent = src
|
|
1105
|
+
}
|
|
1106
|
+
wrap.appendChild(gutter)
|
|
1107
|
+
wrap.appendChild(code)
|
|
1108
|
+
return wrap
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// ---- Bundle items UI ----
|
|
1112
|
+
|
|
1113
|
+
async function renderBundleItems(container, bundleId) {
|
|
1114
|
+
try {
|
|
1115
|
+
const items = await queryTxs({
|
|
1116
|
+
first: 50,
|
|
1117
|
+
bundledIn: [bundleId],
|
|
1118
|
+
}).catch(() => null)
|
|
1119
|
+
|
|
1120
|
+
// Also try bundledIn filter via owner query (items reference parent)
|
|
1121
|
+
let edges = items?.edges || []
|
|
1122
|
+
|
|
1123
|
+
// If that didn't find anything, try a broader approach
|
|
1124
|
+
if (edges.length === 0) return
|
|
1125
|
+
|
|
1126
|
+
const sec = document.createElement("div")
|
|
1127
|
+
sec.className = "section bundle-items"
|
|
1128
|
+
sec.innerHTML = `<div class="section-title">Bundle Items (${edges.length})</div>`
|
|
1129
|
+
|
|
1130
|
+
const rows = edges.map(e => {
|
|
1131
|
+
const mt = tagsMap(e.node.tags)
|
|
1132
|
+
return {
|
|
1133
|
+
type: mt["Type"] || "Data",
|
|
1134
|
+
name: mt["Name"] || "\u2014",
|
|
1135
|
+
id: e.node.id,
|
|
1136
|
+
owner: e.node.owner?.address || "\u2014",
|
|
1137
|
+
size: e.node.data?.size || "\u2014",
|
|
1138
|
+
_id: e.node.id,
|
|
1139
|
+
_owner: e.node.owner?.address || "",
|
|
1140
|
+
}
|
|
1141
|
+
})
|
|
1142
|
+
|
|
1143
|
+
sec.appendChild(table(
|
|
1144
|
+
[
|
|
1145
|
+
{ key: "type", label: "Type", render: v => typeBadgeHtml(v) },
|
|
1146
|
+
{ key: "name", label: "Name" },
|
|
1147
|
+
{ key: "id", label: "ID", mono: true, render: v => `<span class="link">${short(v)}</span>` },
|
|
1148
|
+
{ key: "owner", label: "Owner", mono: true, render: (v, r) => r._owner ? `<span class="link" onclick="event.stopPropagation();location.hash='#/entity/${r._owner}'">${short(v)}</span>` : v },
|
|
1149
|
+
{ key: "size", label: "Data Size" },
|
|
1150
|
+
],
|
|
1151
|
+
rows,
|
|
1152
|
+
row => navigate("#/entity/" + row._id),
|
|
1153
|
+
))
|
|
1154
|
+
|
|
1155
|
+
container.appendChild(sec)
|
|
1156
|
+
} catch {
|
|
1157
|
+
// ok
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
async function loadComputeResult(container, mid, pid) {
|
|
1162
|
+
// Check cache first
|
|
1163
|
+
const cached = getCachedResult(mid)
|
|
1164
|
+
if (cached) {
|
|
1165
|
+
renderComputeOutput(container, cached)
|
|
1166
|
+
return cached
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// Auto-load
|
|
1170
|
+
const loading = document.createElement("div")
|
|
1171
|
+
loading.className = "loading"
|
|
1172
|
+
loading.style.padding = "12px"
|
|
1173
|
+
loading.textContent = "Loading compute result..."
|
|
1174
|
+
container.appendChild(loading)
|
|
1175
|
+
|
|
1176
|
+
try {
|
|
1177
|
+
const result = await getResult(mid, pid)
|
|
1178
|
+
loading.remove()
|
|
1179
|
+
setCachedResult(mid, result)
|
|
1180
|
+
renderComputeOutput(container, result)
|
|
1181
|
+
return result
|
|
1182
|
+
} catch (err) {
|
|
1183
|
+
loading.remove()
|
|
1184
|
+
const errDiv = document.createElement("div")
|
|
1185
|
+
errDiv.className = "loading"
|
|
1186
|
+
errDiv.style.padding = "8px"
|
|
1187
|
+
errDiv.textContent = err.message || "Failed to fetch compute result"
|
|
1188
|
+
container.appendChild(errDiv)
|
|
1189
|
+
return null
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// ---- Message ----
|
|
1194
|
+
|
|
1195
|
+
async function renderMessage(el, node, tags) {
|
|
1196
|
+
el.innerHTML = ""
|
|
1197
|
+
const action = tags["Action"] || null
|
|
1198
|
+
const header = detailHeader("Message", node.id, action)
|
|
1199
|
+
|
|
1200
|
+
const target = node.recipient || tags["Target"]
|
|
1201
|
+
const pushedFor = tags["Pushed-For"]
|
|
1202
|
+
const fromProcess = tags["From-Process"]
|
|
1203
|
+
const fieldRows = [
|
|
1204
|
+
["Action", tags["Action"] || "\u2014"],
|
|
1205
|
+
["From", link(node.owner?.address, node.owner?.address)],
|
|
1206
|
+
["To (Process)", target ? link(target, target) : "\u2014"],
|
|
1207
|
+
]
|
|
1208
|
+
if (pushedFor) fieldRows.push(["Parent Message", link(pushedFor, pushedFor)])
|
|
1209
|
+
if (fromProcess) fieldRows.push(["From Process", link(fromProcess, fromProcess)])
|
|
1210
|
+
fieldRows.push(
|
|
1211
|
+
["Block", node.block?.height ?? "\u2014"],
|
|
1212
|
+
["Timestamp", formatDate(node.block?.timestamp)],
|
|
1213
|
+
["Data Size", node.data?.size ? node.data.size + " bytes" : "\u2014"],
|
|
1214
|
+
)
|
|
1215
|
+
const fields = detailFields(fieldRows)
|
|
1216
|
+
el.appendChild(twoCol(header, fields, section("Tags", renderTags(node.tags))))
|
|
1217
|
+
|
|
1218
|
+
// Data — auto-load
|
|
1219
|
+
if (parseInt(node.data?.size || "0") > 0) {
|
|
1220
|
+
const dataSection = document.createElement("div")
|
|
1221
|
+
dataSection.className = "section"
|
|
1222
|
+
dataSection.innerHTML = '<div class="section-title">Data</div>'
|
|
1223
|
+
el.appendChild(dataSection)
|
|
1224
|
+
renderDataViewer(dataSection, node.id, tags["Action"], node)
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// Compute Result — auto-load with caching
|
|
1228
|
+
let computeResult = null
|
|
1229
|
+
if (target) {
|
|
1230
|
+
const resultSection = document.createElement("div")
|
|
1231
|
+
resultSection.className = "section"
|
|
1232
|
+
resultSection.innerHTML = '<div class="section-title">Compute Result</div>'
|
|
1233
|
+
el.appendChild(resultSection)
|
|
1234
|
+
computeResult = await loadComputeResult(resultSection, node.id, target)
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// Message Tree — always show, with parent-child relationships
|
|
1238
|
+
// Find child messages + parent action in parallel
|
|
1239
|
+
let childMsgs = []
|
|
1240
|
+
let parentAction = null
|
|
1241
|
+
{
|
|
1242
|
+
const promises = []
|
|
1243
|
+
promises.push(
|
|
1244
|
+
queryTxs({
|
|
1245
|
+
first: 50,
|
|
1246
|
+
tags: [
|
|
1247
|
+
{ name: "Type", values: ["Message"] },
|
|
1248
|
+
{ name: "Pushed-For", values: [node.id] },
|
|
1249
|
+
],
|
|
1250
|
+
sort: "HEIGHT_DESC",
|
|
1251
|
+
}).then(r => { childMsgs = r?.edges || [] }).catch(() => {})
|
|
1252
|
+
)
|
|
1253
|
+
if (pushedFor) {
|
|
1254
|
+
promises.push(
|
|
1255
|
+
queryTxs({ ids: [pushedFor] }).then(r => {
|
|
1256
|
+
const pt = tagsMap(r?.edges?.[0]?.node?.tags)
|
|
1257
|
+
parentAction = pt["Action"] || null
|
|
1258
|
+
}).catch(() => {})
|
|
1259
|
+
)
|
|
1260
|
+
}
|
|
1261
|
+
await Promise.all(promises)
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
{
|
|
1265
|
+
const treeSection = document.createElement("div")
|
|
1266
|
+
treeSection.className = "section"
|
|
1267
|
+
treeSection.innerHTML = '<div class="section-title">Message Flow</div>'
|
|
1268
|
+
|
|
1269
|
+
treeSection.appendChild(renderMessageTree(node, tags, childMsgs, computeResult, pushedFor, parentAction))
|
|
1270
|
+
el.appendChild(treeSection)
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
// ---- Module ----
|
|
1276
|
+
|
|
1277
|
+
async function renderModule(el, node, tags) {
|
|
1278
|
+
el.innerHTML = ""
|
|
1279
|
+
const name = tags["Name"] || tags["Module-Name"] || null
|
|
1280
|
+
const header = detailHeader("Module", node.id, name)
|
|
1281
|
+
const fields = detailFields([
|
|
1282
|
+
["Owner", link(node.owner?.address, node.owner?.address)],
|
|
1283
|
+
["Name", tags["Name"] || tags["Module-Name"] || "\u2014"],
|
|
1284
|
+
["Format", tags["Module-Format"] || tags["Content-Type"] || "\u2014"],
|
|
1285
|
+
["Memory Limit", tags["Memory-Limit"] || "\u2014"],
|
|
1286
|
+
["Compute Limit", tags["Compute-Limit"] || "\u2014"],
|
|
1287
|
+
["Input Encoding", tags["Input-Encoding"] || "\u2014"],
|
|
1288
|
+
["Output Encoding", tags["Output-Encoding"] || "\u2014"],
|
|
1289
|
+
["Block", node.block?.height ?? "\u2014"],
|
|
1290
|
+
["Timestamp", formatDate(node.block?.timestamp)],
|
|
1291
|
+
["Data Size", node.data?.size ? node.data.size + " bytes" : "\u2014"],
|
|
1292
|
+
])
|
|
1293
|
+
el.appendChild(twoCol(header, fields, section("Tags", renderTags(node.tags))))
|
|
1294
|
+
|
|
1295
|
+
// Processes using this module
|
|
1296
|
+
try {
|
|
1297
|
+
const procs = await queryTxs({
|
|
1298
|
+
first: 50,
|
|
1299
|
+
tags: [
|
|
1300
|
+
{ name: "Type", values: ["Process"] },
|
|
1301
|
+
{ name: "Module", values: [node.id] },
|
|
1302
|
+
],
|
|
1303
|
+
sort: "HEIGHT_DESC",
|
|
1304
|
+
})
|
|
1305
|
+
const procEdges = procs?.edges || []
|
|
1306
|
+
const rows = procEdges.map((e) => {
|
|
1307
|
+
const pt = tagsMap(e.node.tags)
|
|
1308
|
+
return {
|
|
1309
|
+
name: pt["Name"] || "\u2014",
|
|
1310
|
+
id: e.node.id,
|
|
1311
|
+
owner: e.node.owner?.address,
|
|
1312
|
+
time: fromNow(e.node.block?.timestamp),
|
|
1313
|
+
_id: e.node.id,
|
|
1314
|
+
_owner: e.node.owner?.address || "",
|
|
1315
|
+
}
|
|
1316
|
+
})
|
|
1317
|
+
if (rows.length) {
|
|
1318
|
+
el.appendChild(section(
|
|
1319
|
+
`Processes (${procEdges.length})`,
|
|
1320
|
+
table(
|
|
1321
|
+
[
|
|
1322
|
+
{ key: "name", label: "Name" },
|
|
1323
|
+
{ key: "id", label: "ID", mono: true, render: (v) => `<span class="link">${short(v)}</span>` },
|
|
1324
|
+
{ key: "owner", label: "Owner", mono: true, render: (v, r) => `<span class="link" onclick="event.stopPropagation();location.hash='#/entity/${r._owner}'">${short(v)}</span>` },
|
|
1325
|
+
{ key: "time", label: "Time" },
|
|
1326
|
+
],
|
|
1327
|
+
rows,
|
|
1328
|
+
(row) => navigate("#/entity/" + row._id),
|
|
1329
|
+
),
|
|
1330
|
+
))
|
|
1331
|
+
} else {
|
|
1332
|
+
el.appendChild(section("Processes", document.createTextNode("No processes using this module")))
|
|
1333
|
+
}
|
|
1334
|
+
} catch {
|
|
1335
|
+
// ok
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// ---- Block ----
|
|
1340
|
+
|
|
1341
|
+
async function renderBlock(el, height) {
|
|
1342
|
+
const blocks = await queryBlocks({ first: 1, min: height, max: height })
|
|
1343
|
+
const edge = blocks?.edges?.[0]
|
|
1344
|
+
if (!edge) {
|
|
1345
|
+
el.innerHTML = `<div class="loading">Block ${height} not found</div>`
|
|
1346
|
+
return
|
|
1347
|
+
}
|
|
1348
|
+
await renderBlockNode(el, edge.node)
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
async function renderBlockNode(el, node) {
|
|
1352
|
+
el.innerHTML = ""
|
|
1353
|
+
el.appendChild(detailHeader("Block", String(node.height), `Block #${node.height}`))
|
|
1354
|
+
|
|
1355
|
+
el.appendChild(detailFields([
|
|
1356
|
+
["Block ID", node.id],
|
|
1357
|
+
["Height", node.height],
|
|
1358
|
+
["Timestamp", formatDate(node.timestamp)],
|
|
1359
|
+
["Previous", node.previous ? link(node.previous, node.previous) : "\u2014"],
|
|
1360
|
+
]))
|
|
1361
|
+
|
|
1362
|
+
try {
|
|
1363
|
+
const txs = await queryTxs({ first: 100, sort: "HEIGHT_DESC" })
|
|
1364
|
+
const blockTxs = (txs?.edges || []).filter((e) => e.node.block?.height === node.height && !e.node.bundledIn?.id)
|
|
1365
|
+
if (blockTxs.length) {
|
|
1366
|
+
const rows = blockTxs.map((e) => {
|
|
1367
|
+
const tags = tagsMap(e.node.tags)
|
|
1368
|
+
return {
|
|
1369
|
+
type: tags["Bundle-Format"] ? "Bundle" : tags["Type"] || contentTypeLabel(e.node.data?.type || tags["Content-Type"]) || "TX",
|
|
1370
|
+
id: e.node.id,
|
|
1371
|
+
owner: e.node.owner?.address,
|
|
1372
|
+
_id: e.node.id,
|
|
1373
|
+
_owner: e.node.owner?.address || "",
|
|
1374
|
+
}
|
|
1375
|
+
})
|
|
1376
|
+
el.appendChild(section(
|
|
1377
|
+
`Transactions (${blockTxs.length})`,
|
|
1378
|
+
table(
|
|
1379
|
+
[
|
|
1380
|
+
{ key: "type", label: "Type", render: (v) => typeBadgeHtml(v) },
|
|
1381
|
+
{ key: "id", label: "ID", mono: true, render: (v) => `<span class="link">${short(v)}</span>` },
|
|
1382
|
+
{ key: "owner", label: "Owner", mono: true, render: (v, r) => `<span class="link" onclick="event.stopPropagation();location.hash='#/entity/${r._owner}'">${short(v)}</span>` },
|
|
1383
|
+
],
|
|
1384
|
+
rows,
|
|
1385
|
+
(row) => navigate("#/entity/" + row._id),
|
|
1386
|
+
),
|
|
1387
|
+
))
|
|
1388
|
+
}
|
|
1389
|
+
} catch {
|
|
1390
|
+
// ok
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
// ---- Address ----
|
|
1395
|
+
|
|
1396
|
+
async function renderAddress(el, addr, txs) {
|
|
1397
|
+
el.innerHTML = ""
|
|
1398
|
+
el.appendChild(detailHeader("Address", addr))
|
|
1399
|
+
|
|
1400
|
+
const rows = txs.edges.map((e) => {
|
|
1401
|
+
const tags = tagsMap(e.node.tags)
|
|
1402
|
+
return {
|
|
1403
|
+
type: tags["Type"] || contentTypeLabel(e.node.data?.type || tags["Content-Type"]) || "TX",
|
|
1404
|
+
id: e.node.id,
|
|
1405
|
+
recipient: e.node.recipient || "\u2014",
|
|
1406
|
+
time: fromNow(e.node.block?.timestamp),
|
|
1407
|
+
_id: e.node.id,
|
|
1408
|
+
_recipient: e.node.recipient || "",
|
|
1409
|
+
}
|
|
1410
|
+
})
|
|
1411
|
+
el.appendChild(section(
|
|
1412
|
+
`Transactions (${txs.edges.length})`,
|
|
1413
|
+
table(
|
|
1414
|
+
[
|
|
1415
|
+
{ key: "type", label: "Type", render: (v) => typeBadgeHtml(v) },
|
|
1416
|
+
{ key: "id", label: "ID", mono: true, render: (v) => `<span class="link">${short(v)}</span>` },
|
|
1417
|
+
{ key: "recipient", label: "Recipient", mono: true, render: (v, r) => r._recipient ? `<span class="link" onclick="event.stopPropagation();location.hash='#/entity/${r._recipient}'">${short(v)}</span>` : v },
|
|
1418
|
+
{ key: "time", label: "Timestamp" },
|
|
1419
|
+
],
|
|
1420
|
+
rows,
|
|
1421
|
+
(row) => navigate("#/entity/" + row._id),
|
|
1422
|
+
),
|
|
1423
|
+
))
|
|
1424
|
+
|
|
1425
|
+
// Also show messages sent by this address
|
|
1426
|
+
try {
|
|
1427
|
+
const msgs = await queryTxs({
|
|
1428
|
+
first: 50,
|
|
1429
|
+
owners: [addr],
|
|
1430
|
+
tags: [{ name: "Type", values: ["Message"] }],
|
|
1431
|
+
sort: "HEIGHT_DESC",
|
|
1432
|
+
})
|
|
1433
|
+
const msgEdges = msgs?.edges || []
|
|
1434
|
+
if (msgEdges.length) {
|
|
1435
|
+
el.appendChild(section(
|
|
1436
|
+
`Messages Sent (${msgEdges.length})`,
|
|
1437
|
+
msgTable(msgEdges),
|
|
1438
|
+
))
|
|
1439
|
+
}
|
|
1440
|
+
} catch {
|
|
1441
|
+
// ok
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// ---- Generic ----
|
|
1446
|
+
|
|
1447
|
+
async function renderGeneric(el, node, tags, type) {
|
|
1448
|
+
el.innerHTML = ""
|
|
1449
|
+
const header = detailHeader(type, node.id)
|
|
1450
|
+
const fields = detailFields([
|
|
1451
|
+
["Owner", link(node.owner?.address, node.owner?.address)],
|
|
1452
|
+
["Recipient", node.recipient ? link(node.recipient, node.recipient) : "\u2014"],
|
|
1453
|
+
["Block", node.block?.height ?? "\u2014"],
|
|
1454
|
+
["Timestamp", formatDate(node.block?.timestamp)],
|
|
1455
|
+
["Data Size", node.data?.size ? node.data.size + " bytes" : "\u2014"],
|
|
1456
|
+
])
|
|
1457
|
+
el.appendChild(twoCol(header, fields, section("Tags", renderTags(node.tags))))
|
|
1458
|
+
|
|
1459
|
+
// For bundles, show item list instead of raw binary
|
|
1460
|
+
if (tags["Bundle-Format"]) {
|
|
1461
|
+
const bundleSection = document.createElement("div")
|
|
1462
|
+
bundleSection.className = "section"
|
|
1463
|
+
bundleSection.innerHTML = '<div class="section-title">Bundle Items</div>'
|
|
1464
|
+
el.appendChild(bundleSection)
|
|
1465
|
+
await renderBundleItems(bundleSection, node.id)
|
|
1466
|
+
} else {
|
|
1467
|
+
const dataSection = document.createElement("div")
|
|
1468
|
+
dataSection.className = "section"
|
|
1469
|
+
dataSection.innerHTML = '<div class="section-title">Data</div>'
|
|
1470
|
+
el.appendChild(dataSection)
|
|
1471
|
+
renderDataViewer(dataSection, node.id, null, node)
|
|
1472
|
+
}
|
|
1473
|
+
}
|