feat: init 8e702d60
Steve · 2025-09-18 21:50 10 file(s) · +405 −0
.gitignore (added) +34 −0
1 +
# dependencies (bun install)
2 +
node_modules
3 +
4 +
# output
5 +
out
6 +
dist
7 +
*.tgz
8 +
9 +
# code coverage
10 +
coverage
11 +
*.lcov
12 +
13 +
# logs
14 +
logs
15 +
_.log
16 +
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
17 +
18 +
# dotenv environment variable files
19 +
.env
20 +
.env.development.local
21 +
.env.test.local
22 +
.env.production.local
23 +
.env.local
24 +
25 +
# caches
26 +
.eslintcache
27 +
.cache
28 +
*.tsbuildinfo
29 +
30 +
# IntelliJ based IDEs
31 +
.idea
32 +
33 +
# Finder (MacOS) folder config
34 +
.DS_Store
AGENTS.md (added) +65 −0
1 +
# Project Goal
2 +
3 +
The goal of this project is to develop a comprehensive web component library for EVM blockchain applications. This library will provide reusable, vanilla JavaScript web components that enable developers to integrate blockchain functionality (such as wallet connections, transaction handling, contract interactions, and network management) into their web applications without dependencies on React or other frameworks. It aims to be a framework-agnostic alternative to libraries like wagmi, focusing on simplicity, performance, and broad compatibility.
4 +
5 +
Key objectives:
6 +
- Provide a set of standardized web components for common EVM operations
7 +
- Ensure full TypeScript support for type safety
8 +
- Maintain browser compatibility across modern browsers
9 +
- Follow web component best practices and standards
10 +
- Include comprehensive documentation and examples
11 +
- Support both ESM and UMD module formats
12 +
13 +
# Rules
14 +
15 +
## Development Rules
16 +
- Use vanilla JavaScript/TypeScript only; no React, Vue, or other framework dependencies
17 +
- All components must extend HTMLElement and follow the Custom Elements API
18 +
- Implement Shadow DOM for encapsulation where appropriate
19 +
- Use TypeScript for all source code to ensure type safety
20 +
- Follow semantic versioning (SemVer) for releases
21 +
- Write unit tests for all components using Bun's test runner
22 +
- Ensure all code passes linting with ESLint and type checking with TypeScript
23 +
24 +
## Code Quality Rules
25 +
- Follow the project's coding style (consistent indentation, naming conventions)
26 +
- Use meaningful variable and function names
27 +
- Add JSDoc comments for all public APIs
28 +
- Avoid global state; encapsulate state within components
29 +
- Handle errors gracefully and provide meaningful error messages
30 +
- Optimize for performance; minimize bundle size and runtime overhead
31 +
32 +
## Testing Rules
33 +
- Maintain test coverage above 80% for all components
34 +
- Write both unit tests and integration tests
35 +
- Test components in multiple browsers (Chrome, Firefox, Safari, Edge)
36 +
- Include tests for error scenarios and edge cases
37 +
- Run tests on every commit via CI/CD
38 +
39 +
## Contribution Rules
40 +
- All changes must be submitted via pull requests
41 +
- Include tests and documentation updates with new features
42 +
- Follow conventional commit messages
43 +
- Ensure backward compatibility unless breaking changes are explicitly planned
44 +
- Review and approve pull requests from at least one maintainer
45 +
46 +
## Security Rules
47 +
- Never expose private keys or sensitive data in code
48 +
- Validate all user inputs to prevent injection attacks
49 +
- Use secure random generation for any cryptographic operations
50 +
- Regularly audit dependencies for vulnerabilities
51 +
- Implement proper error handling to avoid information leakage
52 +
53 +
## Build and Deployment Rules
54 +
- Use Bun for building, testing, and running the project
55 +
- Generate both ESM and UMD bundles for distribution
56 +
- Minify production builds to reduce bundle size
57 +
- Publish to npm with proper package.json configuration
58 +
- Maintain a changelog for all releases
59 +
60 +
## Commands
61 +
- `bun run build`: Build the library for production
62 +
- `bun run dev`: Start development server with hot reload
63 +
- `bun test`: Run all tests
64 +
- `bun run lint`: Run ESLint for code quality checks
65 +
- `bun run typecheck`: Run TypeScript type checking
CLAUDE.md (added) +107 −0
1 +
---
2 +
3 +
Default to using Bun instead of Node.js.
4 +
5 +
- Use `bun <file>` instead of `node <file>` or `ts-node <file>`
6 +
- Use `bun test` instead of `jest` or `vitest`
7 +
- Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
8 +
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
9 +
- Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
10 +
- Bun automatically loads .env, so don't use dotenv.
11 +
12 +
## APIs
13 +
14 +
- `Bun.serve()` supports WebSockets, HTTPS, and routes. Don't use `express`.
15 +
- `bun:sqlite` for SQLite. Don't use `better-sqlite3`.
16 +
- `Bun.redis` for Redis. Don't use `ioredis`.
17 +
- `Bun.sql` for Postgres. Don't use `pg` or `postgres.js`.
18 +
- `WebSocket` is built-in. Don't use `ws`.
19 +
- Prefer `Bun.file` over `node:fs`'s readFile/writeFile
20 +
- Bun.$`ls` instead of execa.
21 +
22 +
## Testing
23 +
24 +
Use `bun test` to run tests.
25 +
26 +
```ts#index.test.ts
27 +
import { test, expect } from "bun:test";
28 +
29 +
test("hello world", () => {
30 +
  expect(1).toBe(1);
31 +
});
32 +
```
33 +
34 +
## Frontend
35 +
36 +
Use HTML imports with `Bun.serve()`. Don't use `vite`. HTML imports fully support React, CSS, Tailwind.
37 +
38 +
Server:
39 +
40 +
```ts#index.ts
41 +
import index from "./index.html"
42 +
43 +
Bun.serve({
44 +
  routes: {
45 +
    "/": index,
46 +
    "/api/users/:id": {
47 +
      GET: (req) => {
48 +
        return new Response(JSON.stringify({ id: req.params.id }));
49 +
      },
50 +
    },
51 +
  },
52 +
  // optional websocket support
53 +
  websocket: {
54 +
    open: (ws) => {
55 +
      ws.send("Hello, world!");
56 +
    },
57 +
    message: (ws, message) => {
58 +
      ws.send(message);
59 +
    },
60 +
    close: (ws) => {
61 +
      // handle close
62 +
    }
63 +
  },
64 +
  development: {
65 +
    hmr: true,
66 +
    console: true,
67 +
  }
68 +
})
69 +
```
70 +
71 +
HTML files can import .tsx, .jsx or .js files directly and Bun's bundler will transpile & bundle automatically. `<link>` tags can point to stylesheets and Bun's CSS bundler will bundle.
72 +
73 +
```html#index.html
74 +
<html>
75 +
  <body>
76 +
    <h1>Hello, world!</h1>
77 +
    <script type="module" src="./frontend.tsx"></script>
78 +
  </body>
79 +
</html>
80 +
```
81 +
82 +
With the following `frontend.tsx`:
83 +
84 +
```tsx#frontend.tsx
85 +
import React from "react";
86 +
87 +
// import .css files directly and it works
88 +
import './index.css';
89 +
90 +
import { createRoot } from "react-dom/client";
91 +
92 +
const root = createRoot(document.body);
93 +
94 +
export default function Frontend() {
95 +
  return <h1>Hello, world!</h1>;
96 +
}
97 +
98 +
root.render(<Frontend />);
99 +
```
100 +
101 +
Then, run index.ts
102 +
103 +
```sh
104 +
bun --hot ./index.ts
105 +
```
106 +
107 +
For more information, read the Bun API docs in `node_modules/bun-types/docs/**.md`.
README.md (added) +15 −0
1 +
# Eos
2 +
3 +
To install dependencies:
4 +
5 +
```bash
6 +
bun install
7 +
```
8 +
9 +
To run:
10 +
11 +
```bash
12 +
bun run index.ts
13 +
```
14 +
15 +
This project was created using `bun init` in bun v1.2.20. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
bun.lock (added) +29 −0
1 +
{
2 +
  "lockfileVersion": 1,
3 +
  "workspaces": {
4 +
    "": {
5 +
      "name": "idunn",
6 +
      "devDependencies": {
7 +
        "@types/bun": "latest",
8 +
      },
9 +
      "peerDependencies": {
10 +
        "typescript": "^5",
11 +
      },
12 +
    },
13 +
  },
14 +
  "packages": {
15 +
    "@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="],
16 +
17 +
    "@types/node": ["@types/node@24.5.2", "", { "dependencies": { "undici-types": "~7.12.0" } }, "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ=="],
18 +
19 +
    "@types/react": ["@types/react@19.1.13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="],
20 +
21 +
    "bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="],
22 +
23 +
    "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
24 +
25 +
    "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
26 +
27 +
    "undici-types": ["undici-types@7.12.0", "", {}, "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="],
28 +
  }
29 +
}
components/connect-wallet.js (added) +78 −0
1 +
class ConnectWallet extends HTMLElement {
2 +
	constructor() {
3 +
		super();
4 +
		this.attachShadow({ mode: "open" });
5 +
		this.connected = false;
6 +
		this.address = "";
7 +
	}
8 +
9 +
	connectedCallback() {
10 +
		this.render();
11 +
	}
12 +
13 +
	render() {
14 +
		this.shadowRoot.innerHTML = `
15 +
  		<style>
16 +
        :host {
17 +
          --bg-color: ${this.connected ? "#232323" : "#5F8787"};
18 +
          --bg-hover-color: ${this.connected ? "#262626" : "#6F9797"};
19 +
        }
20 +
21 +
        button {
22 +
          padding: 10px 20px;
23 +
          background: var(--bg-color);
24 +
          color: white;
25 +
          border: none;
26 +
          border-radius: 4px;
27 +
          cursor: pointer;
28 +
          font-size: 16px;
29 +
          transition: background-color 0.3s ease;
30 +
        }
31 +
        button:hover {
32 +
          background: var(--bg-hover-color);
33 +
        }
34 +
      </style>
35 +
    `;
36 +
37 +
		const button = document.createElement("button");
38 +
		if (this.connected) {
39 +
			button.textContent = this.truncateAddress(this.address);
40 +
			button.addEventListener("click", () => this.disconnect());
41 +
		} else {
42 +
			button.textContent = "Connect Wallet";
43 +
			button.addEventListener("click", () => this.connect());
44 +
		}
45 +
46 +
		this.shadowRoot.appendChild(button);
47 +
	}
48 +
49 +
	async connect() {
50 +
		if (window.ethereum) {
51 +
			try {
52 +
				const accounts = await window.ethereum.request({
53 +
					method: "eth_requestAccounts",
54 +
				});
55 +
				this.address = accounts[0];
56 +
				this.connected = true;
57 +
				this.render();
58 +
			} catch (error) {
59 +
				console.error("Connection failed", error);
60 +
			}
61 +
		} else {
62 +
			alert("Please install a wallet extension");
63 +
		}
64 +
	}
65 +
66 +
	disconnect() {
67 +
		this.connected = false;
68 +
		this.address = "";
69 +
		this.render();
70 +
	}
71 +
72 +
	truncateAddress(addr) {
73 +
		if (!addr) return "";
74 +
		return addr.slice(0, 6) + "..." + addr.slice(-4);
75 +
	}
76 +
}
77 +
78 +
customElements.define("connect-wallet", ConnectWallet);
index.html (added) +36 −0
1 +
<!DOCTYPE html>
2 +
<html lang="en">
3 +
<head>
4 +
  <meta charset="UTF-8">
5 +
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 +
  <title>Norn</title>
7 +
  <style>
8 +
9 +
    body {
10 +
      background: #121113;
11 +
      color: white;
12 +
      font-family: ui-monospace, "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, "Courier New", monospace;
13 +
      min-height: 100vh;
14 +
      width: 100%;
15 +
    }
16 +
17 +
    .container {
18 +
      display: flex;
19 +
      flex-direction: column;
20 +
      align-items: center;
21 +
      justify-content: center;
22 +
      height: 100vh;
23 +
      width: 100%;
24 +
    }
25 +
26 +
  </style>
27 +
</head>
28 +
<body>
29 +
  <div class="container">
30 +
  <h1>Norn</h1>
31 +
  <connect-wallet></connect-wallet>
32 +
  </div>
33 +
34 +
  <script src="components/connect-wallet.js"></script>
35 +
</body>
36 +
</html>
index.ts (added) +1 −0
1 +
console.log("Hello via Bun!");
package.json (added) +11 −0
1 +
{
2 +
	"name": "eos",
3 +
	"module": "index.ts",
4 +
	"type": "module",
5 +
	"devDependencies": {
6 +
		"@types/bun": "latest"
7 +
	},
8 +
	"peerDependencies": {
9 +
		"typescript": "^5"
10 +
	}
11 +
}
tsconfig.json (added) +29 −0
1 +
{
2 +
  "compilerOptions": {
3 +
    // Environment setup & latest features
4 +
    "lib": ["ESNext"],
5 +
    "target": "ESNext",
6 +
    "module": "Preserve",
7 +
    "moduleDetection": "force",
8 +
    "jsx": "react-jsx",
9 +
    "allowJs": true,
10 +
11 +
    // Bundler mode
12 +
    "moduleResolution": "bundler",
13 +
    "allowImportingTsExtensions": true,
14 +
    "verbatimModuleSyntax": true,
15 +
    "noEmit": true,
16 +
17 +
    // Best practices
18 +
    "strict": true,
19 +
    "skipLibCheck": true,
20 +
    "noFallthroughCasesInSwitch": true,
21 +
    "noUncheckedIndexedAccess": true,
22 +
    "noImplicitOverride": true,
23 +
24 +
    // Some stricter flags (disabled by default)
25 +
    "noUnusedLocals": false,
26 +
    "noUnusedParameters": false,
27 +
    "noPropertyAccessFromIndexSignature": false
28 +
  }
29 +
}