Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .claude/settings.local.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"permissions": {
"allow": [
"Bash(python3:*)",
"Bash(node:*)",
"Bash(npx tsc:*)",
"Bash(pnpm run:*)",
"Bash(mv:*)",
"Bash(pnpm:*)",
"Bash(npx copyfiles:*)",
"Bash(npx tsx:*)",
"Bash(npx prettier:*)",
"Bash(npx eslint:*)",
"Bash(grep -v \"^$\")",
"Bash(mkdir -p /Users/vimchain/Cryptape/ccc/.claude/skills)",
"Bash(mv /Users/vimchain/.claude/skills/ccc-code-style.md /Users/vimchain/Cryptape/ccc/.claude/skills/)",
"Bash(mv /Users/vimchain/.claude/skills/skip-format-build.md /Users/vimchain/Cryptape/ccc/.claude/skills/)",
"Bash(npm show:*)",
"Bash(npm pack:*)",
"Read(//private/tmp/**)",
"Bash(tar -tzf nervosnetwork-fiber-js-0.8.0.tgz)",
"Bash(grep:*)",
"Bash(npm view *)",
"Skill(update-config)",
"Bash(npm info *)",
"Bash(tar -tzf nervosnetwork-fiber-js-0.8.1.tgz)",
"Bash(npm pack *)",
"Bash(mkdir fiber-old *)",
"Bash(tar -xzf nervosnetwork-fiber-js-0.7.1.tgz -C fiber-old)",
"Bash(curl -s \"https://raw.githubusercontent.com/ckb-devrel/ccc/50d657beea36de3ebbd80ee88209842644daef34/packages/core/src/molecule/entity.ts\")"
]
}
}
141 changes: 141 additions & 0 deletions .claude/skills/ccc-code-style.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
---
name: ccc-code-style
description: This skill should be used whenever generating, editing, or reviewing TypeScript code in the CCC (CKBers' Codebase) monorepo — especially packages/core, packages/fiber, or any SDK package. Activates when the user asks to add features, fix bugs, refactor code, or write new modules in this project.
version: 1.0.0
---

# CCC Code Style — `packages/core` Convention

All new code in this repo MUST conform to the conventions derived from `packages/core`. Apply every rule below before finalising any edit.

---

## 1. Comment Style

### JSDoc (mandatory for every exported symbol)
- Use `/** … */` blocks above every exported function, class, type, and constant.
- Include `@param name - description` (dash separator, no type annotation — TypeScript carries the type).
- Include `@returns description` when the return value is non-obvious.
- Include `@example` blocks for conversion helpers and public utilities.
- Include `@see OtherSymbol - one-line note` when a related function exists.
- Mark all public API symbols with `@public`.

```typescript
/**
* Converts a hex string to a Uint8Array.
*
* @param hex - A valid ccc.Hex string starting with "0x".
* @returns The decoded bytes.
* @example
* const bytes = bytesFromHex("0xdeadbeef");
* @see hexFrom - Convert bytes back to a hex string
* @public
*/
export function bytesFromHex(hex: Hex): Bytes { … }
```

### Inline comments
- Use only for non-obvious decisions: V8 optimisations, algorithm tradeoffs, 2's-complement edge cases.
- Never explain what the code does when it is already readable; explain *why*.

### No non-English comments.

---

## 2. Naming Conventions

| Kind | Convention | Examples |
|---|---|---|
| Classes | PascalCase, descriptive suffix | `SignerCkbPrivateKey`, `FiberClient` |
| Abstract / readonly variants | Append `Readonly` | `SignerBtcPublicKeyReadonly` |
| Functions — converters | verb-first `*From` / `*To` | `hexFrom()`, `bytesTo()`, `numFromBytes()` |
| Functions — predicates | `is` prefix | `isHex()`, `isConnected()` |
| Functions — unsafe fast-path | `*Unsafe` suffix | `bytesLenUnsafe()` |
| Types — domain | PascalCase | `Hex`, `Bytes`, `Num` |
| Types — input unions | `*Like` suffix | `HexLike`, `NumLike`, `BytesLike` |
| String enums | PascalCase name, string values | `enum SignerType { EVM = "EVM" }` |
| Union type aliases | PascalCase | `export type HashType = "type" \| "data"` |
| Private/protected fields | trailing underscore | `client_` |
| Files | kebab-case matching export | `signerCkbPrivateKey.ts` |
| Advanced/internal files | `.advanced.ts` suffix | `hash.advanced.ts` |
| Numbers | `bigint` exclusively (`Num = bigint`) | `0n`, `100n` |

---

## 3. Code Structure

### File layout (top → bottom)
1. `import type { … }` — type-only imports first
2. `import { … }` — value imports (relative paths, `.js` extension for ESM)
3. Type aliases and interfaces
4. Constants
5. Exported classes / functions (public API)
6. Internal helpers

### Class layout (top → bottom)
1. `public readonly` properties
2. `protected` / `private` properties (trailing underscore)
3. `constructor`
4. Getters / property accessors
5. Concrete public methods (grouped by feature)
6. Abstract / overridable methods
7. Static factory / utility methods
8. Protected `_*` internal helpers

### Export pattern
- Every package re-exports via `index.ts` barrel: `export * from "./module.js"`
- Unstable / advanced APIs live in a parallel `.advanced.ts` file and are exposed via the `advanced` export entry point (`cccA` namespace).
- Use `export type { … }` for type-only re-exports.

---

## 4. Problem-Breakdown Principles

### Conversion pairs
Every domain type gets explicit `*From()` (parse input → domain type) and `*To()` (domain type → output) functions. Never collapse the two directions into one overloaded function.

### `*Like` input union pattern
Public functions accept a union input type (`HexLike`, `NumLike`) and return the strict domain type. This eliminates overloads and lets callers pass any reasonable format.

```typescript
export type HexLike = Hex | string | Uint8Array | ArrayBuffer | ArrayLike<number>;
export function hexFrom(val: HexLike): Hex { … }
```

### Validated vs. unsafe pairs
When a function is called in hot paths and its input is already validated upstream, provide an `*Unsafe` variant that skips validation. Document the precondition and the performance reason in JSDoc.

### Abstract base class + subclass per chain
Define behaviour contracts with `abstract class`. Extend per-blockchain: `SignerCkbPrivateKey`, `SignerEvmPublicKey`. Use the template-method pattern: abstract leaf methods, concrete orchestration in the base.

### Factory methods
Prefer `static from(input: XLike): X` for synchronous construction and `static async fromString(s: string, client: Client): Promise<X>` for network-dependent construction. Group multiple factories by input kind: `Address.fromScript()`, `Address.fromKnownScript()`.

### Endianness / encoding variants
For multi-format outputs, define named variants: `numLeToBytes()`, `numBeToBytes()`. Let the "default" wrapper call the canonical one.

### Codec abstraction (Molecule)
Serialization concerns live in a `mol.Codec<Input, Output>` wrapper. Domain types do not contain raw encode/decode logic inline; they delegate to a codec object.

### Error messages
Always include the attempted value: `throw Error(\`Invalid hex string: \${v}\`)`. Check preconditions in constructors (fail fast). Never swallow errors silently.

### Async patterns
- Use `async` / `await` throughout; no raw `.then()` chains.
- Parallelise independent async operations with `Promise.all([…])`.
- Internal async helpers are `protected async _methodName()`.

---

## 5. Checklist Before Finishing

- [ ] Every exported symbol has a JSDoc block with `@public`, `@param`, `@returns`.
- [ ] No non-English comments.
- [ ] Input types use `*Like` unions where the caller might reasonably pass multiple formats.
- [ ] Numeric values use `bigint` / `Num`; never `number` for blockchain quantities.
- [ ] Conversion functions follow `*From` / `*To` naming; predicates use `is*`.
- [ ] Private/protected fields use trailing underscore (`client_`).
- [ ] Hot-path variants suffixed `*Unsafe` with precondition documented.
- [ ] Advanced/internal exports separated into `.advanced.ts`.
- [ ] File name matches the primary export in kebab-case.
- [ ] New barrel entries added to the nearest `index.ts`.
34 changes: 34 additions & 0 deletions .claude/skills/ccc-conversions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: ccc-conversions
description: Enforce use of CCC conversion utilities over manual hex/byte/number implementations in this monorepo
version: 1
---

# CCC Conversion Utilities — Mandatory Usage

When writing or modifying code in this repository, always prefer the conversion utilities
exported from `@ckb-ccc/*` packages over manual implementations.

## Preferred utilities

| Need | Use | Never write |
|------|-----|-------------|
| hex string → bigint | `ccc.numFrom(hex)` | `BigInt(hex)`, `parseInt(hex, 16)` |
| number/bigint → hex string | `ccc.numToHex(n)` | `` `0x${n.toString(16)}` `` |
| hex string → `Uint8Array` | `ccc.bytesFrom(hex)` | `Buffer.from(hex.slice(2), "hex")` |
| `Uint8Array` → hex string | `ccc.hexFrom(bytes)` | manual loop / `Buffer.toString("hex")` |
| decimal string → hex | `ccc.numToHex(BigInt(s))` | `` `0x${BigInt(s).toString(16)}` `` |
| CKB hash | `ccc.hashCkb(bytes)` | custom SHA256/blake2b calls |

## Rules

1. **Import source**: import `ccc` from whichever `@ckb-ccc/*` package is already a
dependency of the file (e.g. `@ckb-ccc/connector-react` in demo pages,
`@ckb-ccc/core` in library code).
2. **No raw `BigInt(hex)`** for hex-encoded numbers — use `ccc.numFrom(hex)`.
3. **No manual hex construction** (template literals with `.toString(16)`) — use `ccc.numToHex`.
4. **No `Buffer` / `TextDecoder` for byte↔hex** — use `ccc.bytesFrom` / `ccc.hexFrom`.
5. **Keep display wrappers thin**: if a helper converts a CCC type to a display string
(e.g. `hexToCkb`), it must still delegate the parsing step to a CCC utility.
6. Exception: pure string operations like `maskKey` (slicing, truncating) have no CCC
equivalent and may remain manual.
56 changes: 56 additions & 0 deletions .claude/skills/curly-braces-required.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
name: curly-braces-required
description: This skill applies to every task in this project. It mandates that Claude must ALWAYS wrap control flow bodies (`if`, `else`, `else if`, `for`, `while`, `do`) in curly braces `{}`, even when the body is a single statement. Single-line forms like `if (x) return;` are NEVER acceptable.
version: 1.0.0
---

# Curly Braces Required on All Control Flow Bodies

Every `if`, `else`, `else if`, `for`, `while`, and `do` body **must** be enclosed in `{}`, regardless of how many statements it contains.

## Forbidden patterns

```ts
if (condition) return;
if (condition) doSomething();
for (const x of xs) process(x);
while (running) tick();
```

## Required patterns

```ts
if (condition) {
return;
}

if (condition) {
doSomething();
}

for (const x of xs) {
process(x);
}

while (running) {
tick();
}
```

## Applies to

- All TypeScript / JavaScript files in this repo
- All branches: `if`, `else if`, `else`, ternary bodies are exempt (they are expressions, not statements), but every statement-level branch needs braces
- Early returns, `continue`, `break`, `throw` — no exceptions

## When editing existing code

If you touch a file that already contains brace-free control flow in the lines you are modifying or in immediately surrounding context, fix those occurrences in the same edit. Do not reformat unrelated lines far from your change.

## This rule is unconditional

Do not omit braces even if:
- The body is `return;`, `continue;`, or `break;` — one of the shortest possible statements.
- The original code you are based on uses the brace-free style.
- A linter or formatter would accept the brace-free form.
- The surrounding code uses the brace-free style consistently.
21 changes: 21 additions & 0 deletions packages/demo/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,27 @@ const nextConfig = {
experimental: {
optimizePackageImports: ["@ckb-ccc/core", "@ckb-ccc/core/bundle"],
},
// SharedArrayBuffer (@nervosnetwork/fiber-js WASM) requires a cross-origin
// isolated document: Cross-Origin-Opener-Policy + Cross-Origin-Embedder-Policy.
//
// COOP: same-origin breaks window.opener for cross-origin wallet popups,
// so it is scoped to /connected/Fiber only; signing flows use a dedicated
// same-origin route without these headers where needed (e.g. sign proxy).
//
// COEP credentialless isolates without requiring CORP on every subresource
// (unlike require-corp), which suits the demo shell + CDN assets.
async headers() {
return [
{
source: "/(.*)",
headers: [
{ key: "Cross-Origin-Resource-Policy", value: "cross-origin" },
{ key: "Cross-Origin-Opener-Policy", value: "same-origin" },
{ key: "Cross-Origin-Embedder-Policy", value: "require-corp" },
],
},
];
},
};

export default nextConfig;
1 change: 1 addition & 0 deletions packages/demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@eslint/eslintrc": "^3.3.1",
"@headlessui/react": "^2.2.7",
"@heroicons/react": "^2.2.0",
"@nervosnetwork/fiber-js": "0.8.1",
"@scure/bip32": "^2.0.0",
"@scure/bip39": "^2.0.0",
"@tailwindcss/postcss": "^4.1.12",
Expand Down
Loading
Loading